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

최근에 받은 트랙백

글 보관함


Posted on . Written by




수요일의 FAQ 시간입니다. 오늘은 코로나 런타임 에러에 대한 질문들을 다뤄 보겠습니다.




1. My app was working fine and now I’m seeing a pop-up saying an error was found and my app quits. What changed?



안드로이드에서는 build 2013.1030 부터 적용된 건데요, run-time error 가 일어나면 경고창이 뜨고 그 에러에 대한 정보를 보여주게 됩니다. 이전에는 런타임에러가 adb logcat 화면에만 표시되던가 아니면 아무런 표시 없이 지나갔었거든요. 이 기능은 현재 iOS build 에서는 지원되지 않습니다.



2. I don’t remember getting these errors before. Are these real errors?



예 만약 런타임 에러가 났다면 exception이 일어났기 때문입니다. 그러면 그 프로그램은 그 에러 이후의 코드를 실행하지 않습니다. 여러 에러가 있어도 그 에러가 한번에 다 표시되는 게 아니거든요. 혹은 어떤 특정 디바이스에서만 에러가 일어날 수도 있구요.


일반적으로 이런 에러들은 API 에 의해 nil 값이 return 되서 일어나는 경우가 많습니다. 예를 들어 객체의 포인터가 nil일 때 Corona 객체를 remove 하는 경우를 들어보죠. 그리고 nil인 값을 return 한 것을 받아서 그 스트링을 연결하고 display 하는 경우도 예를 들 수 있습니다. 일반적으로 그 값을 사용하려는 함수의 out of scope 인 경우가 많습니다.



Here is one example:


local touchRect = display.newRoundedRect( 0, 50, 70, 30, 10 )
touchRect.x = display.contentCenterX

local count1 = 0
local count2 = 0
local count3 = 0
        
function touchRect:touch( event )
    if event.phase == "ended" then
        count1 = count1 + 1
        count2 = count2 + 1
        count3 = count3 + 1

        text1.text = "Count1 = " .. count1
        text2.text = "Count2 = " .. count2    -- << error here
        text3.text = "Count3 = " .. count3        
    end
    
    return true
end

text1 = display.newText( "Count1 = 0", 10, 100, native.systemFont, 20 )
local text2 = display.newText( "Count2 = 0", 10, 140, native.systemFont, 20 )
text3 = display.newText( "Count3 = 0", 10, 170, native.systemFont, 20 )

touchRect:addEventListener( "touch" )


하얀 사각형을 두드리면 한번에 3개의 count 가 증가하고 그 증가된 값이 display 됩니다. text2.text 가 세팅될 때 버그가 있는데요. 그 에러는 "attempt to index global 'text2' (a nil value)" 입니다. 이유는 text2가 로컬 변수로 정의 됐고 또 touch 함수 이후에 정의 됐기 때문이죠. 이 경우가 바로 함수의 out of scope (범위 밖) 에서 정의 된 것으로 그 값이 nil 이 되는 경우입니다.

시뮬레이터에서 위 코드를 실행하고 사각형을 두드리면 첫번째 counter 가 증가되는 것까지 보실 수 있을 겁니다. 왜냐하면 text2.text 부분에서 에러가 났기 때문이죠. 그 이후의 코드는 실행이 되지 않습니다. 그 사각형을 계속 두드릴 수 있습니다. 그러면 첫번째 counter 만 계속 증가할 겁니다. 사용자 입장에서는 프로그램에 에러없이 잘 실행된다고 느낄 수 있죠.


안드로이드 코드에 저희들이 준 변화는 이 경우 런타임 에러를 감지하고 팝업창에 에러가 난 파일 이름과 line number 를 display 하도록 했습니다. 그러면 그 라인 이후의 코드는 아직 실행이 안 됐다는 것을 알 수 있죠. 이 메세지를 보시려면 콘솔 윈도우를 열어 놓으셔야 합니다. (iOS 에서는 Xcode 가 될 테고 안드로이드 에서는 adb logcat 이 되겠죠.)

위 에러는 text2를 함수가 정의되기 이전에 정의해 버리면 쉽게 고칠 수 있습니다. 혹은 text2에서 local을 없애서 정의 해도 되죠.


text2 = display.newText( "Count2 = 0", 10, 140, native.systemFont, 20 )



3. How do I keep the pop-up from happening when I release my app to Google Play?



이 팝업을 피하는 방법은 두가지가 있습니다.


1) 모든 버그를 찾아서 고치기
2) 문제가 발생할 수 있는 코드 부근에 pcall 구문을 추가하기

앱에서 모든 버그를 찾아서 고치는건 불가능에 가깝습니다. 그래서 에러를 trap 하고 이 에러를 어떻게 할 것인지 선택할 수 있는 런타임 리스너를 추가할 계획을 가지고 있습니다. 앱 스토어용으로 앱을 빌드하고 유저가 에러가 있는 앱을 실행하면 로그가 기록되서 여러분 서버로 이것을 보낼지 아니면 그냥 넘어갈지를 선택해서 실행할 수 있게 됩니다. 이 기능은 현재는 지원되지 않구요 조만간 업데이트 될 Daily Build 에 적용 될 예정입니다.


4. Is there any way to trap the errors myself and not have it quit the app or display a pop-up to the user?



새로운 런타임 에러 리스너가 포함되게 될 Daily Build 를 기다리기 전에 여러분이 하실 수 있는 방법이 있습니다. Lua pcall 구문으로 여러분 코드 블럭을 감싸서 에러를 trap 할 수 있습니다. pcall (protected call) 은 execution status 를 return 하는 call 로 어떤 함수나 메소드든지 call 할 수 있습니다. call 이 제대로 실행 됐다면 true 를 반환할 것이고 런타임 에러 때문에 실패 했다면 false를 반환할 겁니다. 일단 런타임 에러를 trap 하면 pop-up을 띄우거나 app을 quit 하지 않을 겁니다. pcall을 사용하면 약간의 overhead 가 있을 수 있습니다. 그러니까 꼭 에러를 감지해서 어떤 일을 해야 할 경우에만 사용하시기 바랍니다.


The syntax of pcall is:

pcall( f [, ...] )



where f is the function to be called,
and ... is the arguments for the function.

이 구문을 연습해 보기 위해 함수 안의 text2 세팅 부분을 감싸봤습니다. 그리고 이것을 pcall 을 사용해서 call 했습니다. 이 call 의 결과는 status 에 저장이 되서 display 될 겁니다.


local touchRect = display.newRoundedRect( 0, 50, 70, 30, 10 )
touchRect.x = display.contentCenterX

local count1 = 0
local count2 = 0
local count3 = 0

local function setText2( value )
    text2.text = "Count2 = " .. value
end
        
function touchRect:touch( event )
    if event.phase == "ended" then
        count1 = count1 + 1
        count2 = count2 + 1
        count3 = count3 + 1

        text1.text = "Count1 = " .. count1
        
        local status = pcall( setText2, count2 )
        print( "pcall status is ", status )
        
        text3.text = "Count3 = " .. count3        
    end
    
    return true
end

text1 = display.newText( "Count1 = 0", 10, 100, native.systemFont, 20 )
local text2 = display.newText( "Count2 = 0", 10, 140, native.systemFont, 20 )
text3 = display.newText( "Count3 = 0", 10, 170, native.systemFont, 20 )

touchRect:addEventListener( "touch" )


위 코드를 실행시키면 pcall status 가 false가 될 겁니다. 즉 런타임 에러가 났다는 것이죠. counter 1하고 3은 증가할 겁니다. 즉 pcall 이 런타임 에러를 trap 하고 그 안에 런타임 에러가 있더라도 이후의 코드가 실행된다는 것을 알 수 있을 겁니다.

pcall 은 여러분 코드 중에 fail 일 것 같은 구문이 있고 그 부분을 테스트하거나 guard 하고 싶을 때 사용하실 수 있을 겁니다.



5. Why is the error pop-up only in Android builds?



일단 안드로이드쪽을 작업했습니다. 그 이유는 안드로이드 빌드와 관련해서 default permission들을 없애면서 이 에러들을 다뤄야 할 필요성을 느꼈었거든요. 개발자들에게 이 에러들을 감지하고 trap 하는 기능이 제공되면 아주 유용할 거라고 생각했습니다. 그리고 이 기능을 iOS에도 적용할 거고 Mac 과 윈도우즈 시뮬레이터에도 적용할 계획입니다.

현재 릴리즈 버전과 Daily build 에서는 여러분 앱의 버그를 찾을 수 있도록 하기 위해 런타임 에러 정보를 제공합니다. developer build 를 할 때 파일이름과 line number 그리고 에러의 type 을 콘솔을 통해 보실 수 있을 겁니다. Release build (앱 스토어용)에서는 에러 type 만 보실 수 있습니다.


추가적으로 말씀 드린다면 맥 시뮬레이터를 사용하신다면 Corona Simulator가 아니라  Corona Terminal을 start 하는 걸 잊지 마세요. Corona Terminal 은 console 창을 띄우고 나서 Corona Simulator를 실행할 겁니다. 이 콘솔창에는 print, warning 그리고 에러 메세지 등이 display 될 겁니다.


여기까지가 오늘의 FAQ입니다. 도움이 되셨기를 바랍니다.

반응형

Comment