반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
Posted on . Written by


external modules 를 require 할 때 정확히 어떤 일이 일어나는지 헛갈릴 때가 있습니다. 더군다나 스토리보드 scene들이나 여러분의 custom module들과 같이 동작을 하는데 에상하지 못했던 결과가 나오면 더 혼동되죠.

오늘은 여러분과 같이 Lua 에서 module들은 정확히 어떻게 작동을 하는지에 대해 몇가지 실습을 해 보고 설명도 덧 붙이겠습니다. 이 글을 읽으시면 모듈 내의 코드가 실행되거나 built-in require() function 을 call 했을 때 어떤 코드가 run 하지 않는지 등에 대해 이해 하실 수 있을 겁니다.





Including External Modules


가장 간단한 형식은 external module이 테이블 같은 어떤 것을 return 하는 Lua 파일인 경우입니다. 외부 모듈이 하나의 function 인 셈이죠.

아래 정말 간단한 모듈이 있습니다. example1.lua 인데요. 터미널에 한 문장을 print 하고 빈 테이블을 return 하는 것입니다.


example1.lua


local t = {}

print( "example1.lua has been loaded." )

return t


이제 main.lua를 볼까요? 여기서 우선 example1.lua를 require 합니다.


main.lua


local ex1 = require "example1"

ex1.testvar = "Hello world"



예상한대로 ex1은 빈 테이블입니다. example1.lua에서 빈 테이블을 return 했으니까요. 그리고 “example1.lua has been loaded.” 라는 문장이 터미널에 쓰여질 겁니다. 그 다음에 위에 보면 ex1 테이블에 어떤 프로퍼티를 할당했습니다.

이 부분을 주목해 보세요. 여기 약간의 트릭이 있습니다. 다른 모듈에서 이 example1.lua를 require 해 봅시다. scene1.lua라는 모듈에서요. 이미 main.lua에서 example1.lua를 require 했었죠. 이제 어떤 일이 일어나는지 볼까요?


scene1.lua (previous main.lua still applies)


-- ...

local examp1 = require "example1"
print( examp1.testvar )

-- ...

scene1.lua에서 example1.lua를 require 하면 “example1.lua has been loaded” 이 터미널에 뿌려지지 않습니다. 그리고  ex1.testvar 값을 print 하면 터미널에 “Hello World” 가 뿌려집니다. (이 의미는 뭐냐하면 testvar 프로퍼티가 존재한다는 것이죠.


여기서 뭘 알 수 있나요?


첫번쨰로 “example1.lua has been loaded” 라는 문장에 터미널에 뿌려지지 않은 이유는 그 모듈이 이미 main.lua에서 로드 됐기 때문이죠. 모듈이 한번 로드 되면 그 안의 코드가 다 실행되게 되죠. 그리고 모듈의 return 값은 package.loaded라고 하는 글로벌 테이블에 저장됩니다.


여러분이 require를 call 하면 첫번째로 이전에 이 모듈이 이미 로드 된 것인지 아닌지 확인하기 위해 package.loaded table 을 살펴 봅니다. 만약에 있으면 외부 모듈을 새로 require 하는 대신 package.loaded 에 저장된 return value를 return 합니다. 이 return 된 value는 copy가 아니라 reference 입니다. 그러니까 여러분의 모듈이 테이블을 return 한다면 미래에 같은 모듈에 대해 require를 call 하면 같은 테이블을 get 하게 될 겁니다.


만약에 package.loaded 안에 그 모듈이 없으면 그 모듈이 로드 될 겁니다. (그 모듈안의 코드들이 실행 되겠죠.) 그리고 그 모듈의 return value가 package.loaded table안에 저장될 겁니다. (미래에 사용하기 위해 저장하는 거겠죠.) 그래서 두번째에서는 “example1.lua has been loaded.” 이 터미널에 뿌려지지 않은 겁니다. require() 가 call 됐을 떄 global package.loaded table 안에 이미 그 모듈이 존재하면 그 모듈을 re-load 하지 않으니까요.


모듈 안에 있는 코드를 두번 실행하도록 하는 방법에는 두가지가 있습니다.

  1. 코드를 모듈 내에서 함수 안에 넣고 그 함수를 부르는 경우
  2. package.loaded table 에서 그 모듈을 remove 한 다음에 다시 require 하는 경우


첫번째 시나리오에 대한 예제입니다.


example2.lua


local t = {}

print( "example2.lua has been loaded." )

t.hello = function()
    print( 'Hello world.' )
end

return t


main.lua


local ex2 = require "example2"
-- Terminal: example 2 has been loaded.

ex2.hello()
-- Terminal: Hello world.


scene1.lua


local examp2 = require "example2"

examp2.hello()
-- Terminal: Hello world.



예제에서 보듯이 example2.lua를 두개의 다른 모듈(main.lua and scene1.lua)에서 require 했습니다. 첫번째 print statement는 오직 한번 보여집니다. 첫번쨰로 그 모듈이 require 됐을 때죠.

두번째 print statement는 hello() 함수 안에 있습니다. 이것은 hello() 함수가 call 될 때마다 실행되겠죠. 그 코드가 한번 이상 실행되기를 원한다면 함수를 table에 attach 해서 모듈 마지막 부분에서 return 되게 하세요. (또는 단지 require 만 했을 떄 print 되지 않도록 할 때도 그렇게 하면 되겠죠.)


Removing from package.loaded


여러분이 모듈을 require 하려면 (예를 들어 example2.lua) require "example2" 라고 해야 되죠.

그러면 example2.lua의 return value 가 package.loaded table 에 저장 될 겁니다.

package.loaded["example2"]

만약 example2.lua에 있는 코드가 다시 execute 될 필요가 있다면 package.loaded table 에서 remove 한 다음에 다시 call 하시면 됩니다.


아래 그 예제가 있습니다.


main.lua


require "example2"
-- Terminal: example2.lua has been loaded.

package.loaded["example2"] = nil

require "example2"
-- Terminal: example2.lua has been loaded.

require "example2"
-- Terminal:


This is Universal

여러분이 만든 모듈이든 아니면 다운로드 된 모듈이든 혹은 built-in 모듈이든 이 모듈들을 다룰 때는 위에 설명드린 대로 외부 모듈들이 작동합니다.

스토리 보드의 scene들을 다룰 때 그 scene이 로드될 떄 스토리보드 리스너 함수안에 있는 코드들이 어떤 것은 실행되고 어떤 것은 실행되지 않는지에 대한것도 궁금하실 겁니다.

거기에 대한 것은 다음 기회에 다루도록 하겠습니다.

반응형