본문 바로가기

iOS+

Cannot preview in this file

개요

 

프로젝트 앱 코드를 작성하는데 한동안 프리뷰를 안 쓰다가, 프리뷰를 사용해 보려는 어느 순간 오류가 발생했다

어디서 언제 발생하게 되었는지 잘 모르겠어서 오류가 발생할만한 코드를 찾으며 시간을 낭비하고, 결국 Crash Log를 분석해가며 알게 된 내용을 정리한다

 

흔한 오류 해결법

Preview가 안 되는 이유는 여러 가지가 있을 수 있는데, 다음과 같은 방법들로 해결할 수 있다

 

XCode와 관련해서 가장 간단하지만 효과적인 방법으로 XCode 재시작을 하는 것과 Derived Data 삭제Clean Build Folder 수행이다

Derived Data는 XCode가 프로젝트를 빌드할 때 생성하는 임시 파일들을 저장하는 디렉터리다

  • /Users/USERNAME/Library/Developer/Xcode/DerivedData

Clean Build Folder(Cmd+Opt+K)는 빌드 디렉터리의 모든 타겟에 대한 앱파일, dSYM파일, 사전 컴파일된 헤더 파일등을 삭제한다

이 과정에서 Derived Data 디렉토리의 일부 파일들이 삭제된다

 

또한, 코드관련해서는 아마 @Environment로 View에서 받아야 하는데 #Preview 내에서 전달을 안해서 발생했을 확률이 높다

 

Crash Log 분석하기

.ips 파일은 크래시 로그를 저장하는 파일 형식으로, 시스템이 비정상적으로 종료되거나 애플리케이션이 충돌할 때 생성된다

프리뷰 실패 시에도 해당 파일을 생성하는데, 열어보면 다음과 같은 정보가 존재한다

 

  • 프로세스 정보: 충돌이 발생한 프로세스의 이름, PID(프로세스 ID), 실행 경로 등
  • 스레드 정보: 충돌이 발생한 스레드의 스택 트레이스, 레지스터 상태 등
  • 시스템 정보: 운영 체제 버전, 장치 모델, 메모리 상태 등
  • 예외 정보: 충돌을 일으킨 예외의 유형, 원인 등

해당 정보들을 실제로 내가 얻은 .ips 파일에서 찾아보면 다음과 같다

 

레지스터 상태

Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000008   x1: 0x0000000000000001   x2: 0x0000000000000000   x3: 0x0000000000000000
    x4: 0x0000600002234000   x5: 0x0000000000000080   x6: 0x0000000000000000   x7: 0x0000000000000fe0
    x8: 0x0000000000000020   x9: 0x0000000000000103  x10: 0x0000600000262130  x11: 0x0000e35867f40000
   x12: 0x0000000000000030  x13: 0x0000600000e25808  x14: 0x00000000001ff800  x15: 0x00000000000007fb
   x16: 0x0000000000000209  x17: 0x000000020b694390  x18: 0x0000000000000000  x19: 0x0000000000000080
   x20: 0x0000600002234000  x21: 0x0000000000000000  x22: 0x0000000000000000  x23: 0x0000000000000001
   x24: 0x0000000000000008  x25: 0x0000000000000000  x26: 0x000000000000000b  x27: 0x00000002013f7500
   x28: 0x00000002034eaa20   fp: 0x000000016d426790   lr: 0x000000019eedce84
    sp: 0x000000016d426750   pc: 0x000000019eeb6b4c cpsr: 0x40001000
   far: 0x0000000000000000  esr: 0x56000080  Address size fault
  • 일반 목적 레지스터: x0 ~ x28
  • 스택 포인터 (sp)
  • 프레임 포인터 (fp)
  • 프로그램 카운터 (pc)
  • 상태 레지스터 (cpsr) - Current Program Status Register
  • lr (Link Register) - 함수 호출 시 복귀 주소
  • far (Fault Address Register) - 예외가 발생한 주소를 저장
  • esr (Exception Syndrome Register) - 예외의 원인과 관련된 정보를 저장

 

스택 트레이스

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	       0x19eeb6b4c __abort_with_payload + 8
1   libsystem_kernel.dylib        	       0x19eedce84 abort_with_payload_wrapper_internal + 104
2   libsystem_kernel.dylib        	       0x19eedce1c abort_with_reason + 32
3   libobjc.A.dylib               	       0x19eb50040 _objc_fatalv(unsigned long long, unsigned long long, char const*, char*) + 128
4   libobjc.A.dylib               	       0x19eb4ffc0 _objc_fatal(char const*, ...) + 44
5   libobjc.A.dylib               	       0x19eb1a1ac lookUpImpOrForward + 836
6   libobjc.A.dylib               	       0x19eb19b84 _objc_msgSend_uncached + 68
7   ???                           	       0x380034770 ???
8   ???                           	       0x380191b0c ???
9   ???                           	       0x380191a2c ???
10  libswiftCore.dylib            	       0x1afef6d04 swift::MetadataCacheEntryBase<(anonymous namespace)::SingletonMetadataCacheEntry, int>::doInitialization(swift::MetadataWaitQueue::Worker&, swift::MetadataRequest) + 848
11  libswiftCore.dylib            	       0x1afedcd80 swift_getSingletonMetadata + 1892
12  ???                           	       0x38019031c ???
13  ???                           	       0x380191378 ???
14  ???                           	       0x38019143c ???
15  TodoMate                      	       0x100a9a230 __debug_blank_executor_run_user_entry_point + 144
16  PreviewsInjection             	       0x25d89b7b0 0x25d864000 + 227248
17  PreviewsInjection             	       0x25d89c4c8 0x25d864000 + 230600
18  PreviewsInjection             	       0x25d89c38c __previews_injection_run_user_entrypoint + 16
19  XOJITExecutor                 	       0x271d42adc __xojit_executor_run_program_wrapper + 1832
20  XOJITExecutor                 	       0x271d3e7cc 0x271d3b000 + 14284
21  PreviewsInjection             	       0x25d89c2c0 0x25d864000 + 230080
22  TodoMate                      	       0x100a99970 __debug_blank_executor_main + 1056
23  dyld                          	       0x19eb68274 start + 2840
  • dyld : Dynamic Link Editor, 동적 라이브러리를 로드하고 링크하는 역할을 수행하는 시스템 라이브러리
  • XOJITExecutor : 프로그램의 JIT(Just-In-Time) 컴파일러가 실행되며, 코드 실행을 준비
  • PreviewsInjection : 코드에 대한 프리뷰 또는 테스트 실행
  • libswiftCore.dylib : Swift 언어로 작성된 코드의 메타데이터를 초기화하거나 관리
  • libobjc.A.dylib : Objective-C에서는 메서드 호출이 동적으로 이루어지는데 프로그램 실행 중에 메서드를 찾고 호출하는 과정을 처리하는 라이브러리
  • libsystem_kernel.dylib : 운영체제에서 커널 호출을 수행하는 시스템 라이브러리, 여기선 프로그램의 비정상적인 종료를 처리하거나 비정상적인 상태를 알리는 역할로 사용됨

 

맨 아래부터 실행과정을 보면, 앱을 실행하는 것은 사실 동적링킹(dyld) 후에 이뤄지는 것을 알 수 있다

대충 Preview를 위한 처리를 거치고, 잘 수행되다가 libobjc.A.dylib에서 lookUpImpOrForward 후

_objc_fatal이 수행되고 libsystem_kernel.dylib에서 abort_with_reason이 수행된다

 

예외 정보

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000

Termination Reason:    Namespace OBJC, Code 1 

 

SIGABRT 신호는 프로그램이 비정상적인 상태에 도달했음을 나타내고, EXC_CRASH는 크래시가 발생했음을 의미한다

Namespace OBJCCode 1Objective-C 런타임에서 발생한 문제를 나타낸다

 

즉, 정리해 보면 libobjc.A.dylib에서 lookUpImpOrForward에서 메서드를 찾지 못하거나 포워딩하는 과정에서 문제가 발생했고

이로 인해 Objective-C 런타임이 예외를 발생시키고, 프로그램이 abort()를 호출하여 종료된 것이다

 

오류 원인

사실 현재 나의 SwiftUI 앱에서는 새롭게 추가한 Package가 하나밖에 없기에 어디서 발생했는지는 쉽게 알 수 있었다

또한 프리뷰만 안될 뿐, 실제 빌드 후 실행에는 문제가 없었기 때문에 더 확실하게 해당 패키지가 문제일 것이라고 생각했다

 

현재 만들던 앱에서는 Firebase SDK를 이용하는데 아마 여기서 발생하는 것 같아서

새로 프로젝트를 생성하고 import FirebaseCore를 했을 때와 안 했을 때 프리뷰를 수행시켜 보았다

 

그 결과 아무런 요소를 사용하지 않아도 import FirebaseCore를 했다면, 프리뷰에 오류가 발생했다

게다가 패키지만 추가하고, import FirebaseCore 조차 안 해도 프리뷰 오류가 발생했다

그렇다면 도대체 왜 오류가 발생하는 것일까?

 

내용을 보면 나와 비슷한 오류가 발생한 상황에 대해, 링킹과정이 올바르게 이뤄지지 않아서 발생하는 오류고 고쳤다고 한다

하지만 여전히 나한테는 Preview crash 오류가 발생한다

이유를 명확하게는 모르겠으나 Crash 로그 분석에서 보았듯이 Firebase 내부의 Objective-C 코드가 올바르게 매핑이 되지 않아서 발생하는 오류이지 않을까 싶다…

라고 생각하고 있을 때, 생각해 보니 내가 현재 XCode 16을 사용하면서 발생하게 되는 문제인 것 같다

 

마무리

결국 문제를 해결할 수도, 원인을 명확하게 확인할 수도 없어서 찝찝하지만

이번 기회를 토대로 에러로그 분석에 대해 정리해 보면서 앞으로 에러로그를 당황하지 않고 분석할 수 있게 된 것 같다

'iOS+' 카테고리의 다른 글

WidgetKit  (0) 2024.09.15
macOS 앱 배포 정리  (1) 2024.08.31
UserNotifications  (0) 2024.08.11
EventKit  (0) 2024.08.03
MapKit  (0) 2024.07.27