IBDesignable은 xib파일에서 작업한 결과물을 다른 xib나 스토리보드에서 바로바로 확인 할 수 있게 해주는 편리한 툴입니다. 기본적인 사용법은 이 포스트를 참조해주세요.
하지만 안타깝게도, IBDesignable을 사용했을 때 주의하지 않으면 다음과 같은 에러들을 만나게 되기도 합니다.
IBDesignable Crash가 발생해, 인터페이스 빌더에서 아무 것도 “보면서 편집” 할 수 없는 상황입니다.
이런 에러를 만났을 때 제대로 대처하지 못한다면, IBDesignable은 그저 생산성을 저하시키는 툴밖에 되지 않겠죠. 이 글에서는 IBDesignable을 사용하면서 만날 수 있는 에러 메시지들과, 그에 대한 대처법, 주의할 사항을 알아보도록 하겠습니다.
들어가기 전에, 간단한 배경지식
InterfaceBuilder는 iOS Simulator위에서 돌아간다.
IB는 결코 정적인 그림판이 아닙니다. 그것은 실시간으로 돌아가고 있는 Simulator의 화면입니다. 우리가 직접 Command+B를 눌러서 빌드를 하지 않아도, Xcode를 키거나 IB 파일을 열었을 때 Xcode에서 빌드가 돌아가는 이유가 바로 그 때문이죠.
그리고 Simulator는 우리가 Command+R을 눌렀을 때 앱이 올라가는 시뮬레이터와는 별도의 시뮬레이터일 수 있고, 만들어지는 Bundle도 다른 Bundle일 수 있습니다. 이 점만 기억하면 아래의 여러 에러들을 훨씬 쉽게 이해하고 다룰 수 있습니다.
ErrorMessage 1 : Agent Crash
IBDesignables: Failed to update auto layout status: The agent crashed
Plain Text
복사
이런 종류의 메시지가 떴다면, 이는 운이 좋은 경우입니다. IBDeignable을 렌더링하던 시뮬레이터에서 크래시가 발생했기 때문에, 그 크래시 로그가 남게 되고, 그 로그를 분석하면 어디서 문제가 발생했는지 알 수 있기 때문입니다.
cd ~/Library/Logs/DiagnosticReports
ls | grep ‘IBDesignablesAgent-iOS*’ // 이 결과 물 중 가장 최근 파일을 연다.
// 혹은 아예 이 명령을 shellScript로 만들 수도 있습니다.
ls ~/Library/Logs/DiagnosticReports | grep ‘IBDesignablesAgent-iOS*’| tail -1 | xargs open
Shell
복사
위 명령을 치면 다음과 같은 크래시 로그를 볼 수 있습니다.
친절하게도 어떤 파일의 어떤 함수에서 어떤 오류가 발생했는지 상세히 알려줍니다.
기본적으로 IB는 파일의 awakeFromNib과 prepareForInterfaceBuilder 를 실행합니다. 따라서 사실 굳이 크래시 로그를 보지 않더라도, 대부분의 오류는 그 두 군데를 잘 살펴보면 알아낼 수 있습니다. 그리고 사실 그 두 군데에서 크래시를 유발 할 수 있는 실수들도 어느 정도 정해져 있습니다.
1. Bundle.main에서 Asset을 불러오거나 그것을 참조한다.
우리에게 main인 번들이 IB simulator에게는 main이 아닐 수도 있습니다. 따라서 우리가 AssetCatalogue에 넣어둔 Asset들이 IB simulator에서는 nil이 될 수도 있지요. 언제나 Bundle.main을 직접 부르지 말고 Bundle(for: MyViewClass.self)를 통해 Bundler을 참조해야 합니다. 무엇보다도 force-unwrapping은 그냥 전체적으로 하지 않는 것이 좋습니다.
2. 작업중에 nil을 참조하는 코드를 `awakeFromNib` 등에 두고 빌드한다.
개발을 하는 도중에는 말도 안 되는 코드들을 쓰게 될 때가 있다. 예를 들어
let a:String? = nil
let b = a!.count
print(b)
Plain Text
복사
이런 코드가 awkeFromNib이나 prepareForInterfaceBuilder 안에 들어있다면, 우리의 앱이 Crash 나듯, IBAgent도 Crash 납니다.
따라서 `AgetnCrash` 관련 오류가 났다면
1. 실제로 빌드를 해서 실행시켜 본다. 그랬는데 크래시가 나면 당연히 IB에서도 크래시가 난다.
2. 실행시켰는데 크래시가 나지 않는다면, awakeFromNib이나 prepareForInterfaceBuilder에서 Bundle.main을 참조하는 코드가 있지 않은지 확인한다.
주의 사항
1.
CrashLog는 바로바로 만들어지지 않을 수도 있다. 크래시로그는 그 이름에 만들어진 날짜/시간이 표시되므로, 언제나 그 생성시점을 확인하고 읽어야 한다.
2.
때로 CrashLog는 Xcode를 껐다가 켜야 만들어 질 수도 있습니다.
ErrorMessage 2: Library not loaded
이 에러는 좀 더 다루기 까다롭습니다. 디버깅 할 수 있는 방법이 많지 않고, 또 실제로 어떤 문제가 있어서 라이브러리를 로드하는데 실패한건지, 혹은 “아직” 라이브러리를 다 로드하지 못한 것인지 확인하기 어렵기 때문입니다.
본질적으로 이 에러는 다음 사진이랑 비슷한 상황입니다.
Cocoapod을 install하고 빌드를 하지 않으면 당연히 모듈을 불러올 수 없습니다. 이 때는 당연히 pod install → Build하면 문제가 해결됩니다.
문제는 그렇게 했는데도 다음과 같은 에러메시지가 보일 때다.
Library not loaded:@rpath/Alamofire.framework/Alamofire ….
Plain Text
복사
기본적으로 @executable_path/Frameworks와 @loader_path/Frameworks가 설정되어 있습니다. 그런데 안타깝게도 IBAgent와 일반 Simulator 들의 @executable_path/@loader_path 가 다르기 때문에
를 다음과 같이 추가해 줘야 합니다.
ErrorMessage 3 : CodeSign
SomeFramework.framework: required code signature missing for ‘SomeFramework.framework’
Plain Text
복사
이는 IBDesignable을 구현한 Pod을 Cocoapod을 통해 설치했을 때 일어날 수 있는 문제입니다.
기본적으로 IBDesignableAgent는 CodeSign을 요구합니다. 그런데 Cocoapod은 pod install을 할 때 모든 CodeSign을 Disable시킵니다. 대부분의 경우, 어차피 최종 만들어지는 App에만 CodeSign이 되면 전혀 문제가 없지만, IBDesignable의 경우에는 그 자체가 최종 만들어지는 App이기 때문에 문제가 됩니다.
최근의 Cocoapod에서는 문제를 해결한 듯 보이므로, 최신 버전으로 업데이트를 해결 됩니다. 하지만 모종의 이유로 (팀원들과 같은 Cocoapod버전을 써야 한다든지) 업데이트를 할 수 없다면 Podfile에 아래 코드를 추가하면 됩니다.
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
config.build_settings.delete(‘CODE_SIGNING_ALLOWED’)
config.build_settings.delete(‘CODE_SIGNING_REQUIRED’)
end
end
Plain Text
복사
마치며
IBDesigable은 그 자체로 하나의 UITest가 될 수 있습니다. 위와 같은 여러 에러에 대응하기 어려워서 IBDesignable을 쓰지 않고 있었다면, 지금이라도 용기를 내어 다시 시도해 보기를 권합니다.