[Xcode][SwiftUI] Swift runtime failure: Unexpectedly found nil while implicitly unwrapping an Optional value + 0 (:0)[Xcode][SwiftUI] 오류 해결방법
사용자들이 사용하는 앱에서 크래시 리포트가 보고 되었다. 너무 오래만에 스위프트UI 언어를 접하려고 하니 , 새롭게 느껴진다. 사용자에게 오류 없는 어플을 제공하기 위해 오류 해결을 시도하였다.
오류 보고서 내용은 다음과 같다.
Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5
Terminating Process: exc handler [30670]
Thread 0 Crashed:
0 xxxxxxxxxxxx 0x00000001022a33c4 Swift runtime failure: Unexpectedly found nil while implicitly unwrapping an Optional value + 0 (<compiler-generated>:0)
1 xxxxxxxxxxxx 0x00000001022a33c4 CheckBattery.closeAlarmWindow() + 0 (CheckBattery.swift:261)
2 xxxxxxxxxxxx 0x00000001022a33c4 CheckBattery.getBatteryStatus() + 4600 (CheckBattery.swift:145)
3 xxxxxxxxxxxx 0x00000001022a33e0 @objc CheckBattery.getBatteryStatus() + 24 (<compiler-generated>:0)
4 Foundation 0x000000019d30ccfc __NSFireTimer + 104 (NSTimer.m:280)
5 CoreFoundation 0x000000019c130184 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 32 (CFRunLoop.c:1790)
6 CoreFoundation 0x000000019c12fe28 __CFRunLoopDoTimer + 1012 (CFRunLoop.c:2397)
7 CoreFoundation 0x000000019c12f938 __CFRunLoopDoTimers + 356 (CFRunLoop.c:2555)
8 CoreFoundation 0x000000019c1150f0 __CFRunLoopRun + 1856 (CFRunLoop.c:3116)
9 CoreFoundation 0x000000019c114334 CFRunLoopRunSpecific + 572 (CFRunLoop.c:3414)
10 HIToolbox 0x00000001a754d0cc RunCurrentEventLoopInMode + 292 (EventLoop.c:455)
11 HIToolbox 0x00000001a7552ebc ReceiveNextEventCommon + 636 (EventBlocking.c:384)
12 HIToolbox 0x00000001a7553020 _BlockUntilNextEventMatchingListInModeWithFilter + 76 (EventBlocking.c:171)
13 AppKit 0x000000019fc58a70 _DPSNextEvent + 660 (CGDPSReplacement.m:810)
14 AppKit 0x00000001a057e7b8 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688 (appEventRouting.m:509)
15 AppKit 0x000000019fc4bb7c -[NSApplication run] + 480 (NSApplication.m:3642)
16 AppKit 0x000000019fc2244c NSApplicationMain + 888 (NSApplication.m:10475)
17 SwiftUI 0x00000001ca118784 specialized runApp(_:) + 160
18 SwiftUI 0x00000001ca59c30c runApp<A>(_:) + 84 (AppKitApp.swift:15)
19 SwiftUI 0x00000001ca8abbec static App.main() + 224 (App.swift:121)
20 xxxxxxxxxxxx 0x000000010229debc static xxxxxxxxxxxxApp.$main() + 24 (xxxxxxxxxxxxApp.swift:12)
21 xxxxxxxxxxxx 0x000000010229debc main + 36 (TempAlarmView.swift:0)
22 dyld 0x000000019bcac274 start + 2840 (dyldMain.cpp:1334)
Xcode에서 오류 확인하는 방법을 모르는 경우에는 아래 글을 참고하면 도움이 될거야.
[Xcode] App Store Connect 에는 없는 구글플레이콘솔에는 있는 비정상 종료 (Crashes)및 ANR 정보와 같은 정보를 확인하는 방법
위 오류가 예전에 한번 발생되어 처리하였는데, 또 발생되어네..
오류 메시지를 보면 “Unexpectedly found nil while implicitly unwrapping an Optional value”라는 메시지가 있다. 이는 Swift에서 옵셔널 값을 강제로 언래핑하려고 시도했을 때, 해당 값이 nil
인 경우 발생하는 오류이다. 해당 오류가 발생한 위치는 CheckBattery.closeAlarmWindow()
메서드의 CheckBattery.swift:261
에서 발생한 것 같다.
해결 방법
- 옵셔널 강제 언래핑 제거: 강제로 언래핑되는 옵셔널 값을 안전하게 처리하려면 옵셔널 바인딩(
if let
또는guard let
)을 사용해야 한다.예를 들어, 코드에서closeAlarmWindow()
메서드에서 옵셔널을 강제 언래핑하고 있는 부분을 찾아서 수정해야 한다.
// 강제 언래핑 예시
let alarmWindow = someOptionalValue!
이를 옵셔널 바인딩을 통해 안전하게 처리하면:
// 옵셔널 바인딩 예시
if let alarmWindow = someOptionalValue {
// alarmWindow 사용
} else {
// nil일 경우 처리
}
2. 문제 발생 지점 확인: CheckBattery.swift:261
과 CheckBattery.swift:145
에서 오류가 발생했다고 하니, 해당 파일의 해당 줄들을 확인하고 옵셔널 값들이 어떻게 처리되고 있는지 살펴보자.
예를 들어, 다음과 같은 코드가 있을 수 있다:
// 예시 코드
var someOptionalValue: SomeType?
someOptionalValue = nil
// 오류 발생: 옵셔널 강제 언래핑
let value = someOptionalValue!
이를 안전하게 처리하려면 옵셔널 바인딩을 사용하거나, 디폴트 값을 지정하는 방법이 좋다.
3. 디버깅: Xcode에서 해당 코드 위치에 브레이크포인트를 추가하고, nil
값을 반환할 가능성이 있는 변수들을 체크하여 정확히 어떤 값이 nil
인지 확인해 본다.
4. 잠재적 원인:
closeAlarmWindow()
메서드에서 사용하는 객체나 변수가nil
인 경우이다.getBatteryStatus()
메서드에서 옵셔널 값이 강제로 언래핑되고 있을 가능성도 있다.
예시 코드 수정:
// 옵셔널 바인딩으로 수정 예시
func closeAlarmWindow() {
if let alarmWindow = self.alarmWindow {
alarmWindow.close()
} else {
print("알람 창이 없습니다.")
}
}
func getBatteryStatus() {
if let batteryStatus = self.batteryStatus {
// batteryStatus 사용
} else {
print("배터리 상태를 불러올 수 없습니다.")
}
}
이렇게 변경하여 nil
값을 안전하게 처리해 주시면 오류를 방지할 수 있다.
오류 메시지에 있는 코드 줄을 확인하고 위와 같은 방법으로 수정한다.
오류가 발생한 코드는 다음과 같다.
var someWindow: NSWindow!
func closeAlarmWindow() {
SoundSetting.instance.onStopSound()
if (someWindow != nil) {
someWindow.close()
}
}
문제는 someWindow
가 NSWindow!
타입으로 선언되어 있기 때문에, nil
값이 할당되었을 때 강제로 언래핑을 시도하는 것이다. 옵셔널 타입이 nil
일 때 강제로 언래핑을 시도하면 런타임 오류가 발생한다. 그래서 if (someWindow != nil)
로 nil
체크를 하고 있긴 하지만, 이 코드에서 여전히 문제가 발생할 수 있다.
해결 방법 1: 옵셔널 바인딩 사용
someWindow
가 옵셔널이기 때문에, 이를 안전하게 처리하기 위해 옵셔널 바인딩을 사용할 수 있다. if let
을 사용하여 someWindow
가 nil
이 아닌 경우에만 접근하도록 변경할 수 있다.
수정된 코드:
func closeAlarmWindow() {
SoundSetting.instance.onStopSound()
// 옵셔널 바인딩을 사용하여 안전하게 닫기
if let window = someWindow {
window.close()
} else {
print("Window is nil, cannot close it.")
}
}
해결 방법 2: 강제 언래핑을 피하는 방식
someWindow!
를 직접 사용하지 않고, if let
이나 guard let
을 통해 안전하게 처리하는 방법이다.
수정된 코드 (강제 언래핑을 피하는 방식):
func closeAlarmWindow() {
SoundSetting.instance.onStopSound()
// 옵셔널 강제 언래핑을 피하고 안전하게 처리
if someWindow != nil {
someWindow.close()
} else {
print("Window is nil, cannot close it.")
}
}
추가 고려 사항:
NSWindow!
는 암시적 옵셔널이므로,nil
체크 후 안전하게 접근하더라도,nil
값을 다룰 때 예상하지 못한 오류가 발생할 수 있다.NSWindow?
와 같이 일반 옵셔널로 선언하는 것이 좋을 수 있다.- 예를 들어
someWindow
를NSWindow?
로 선언하면,nil
체크를 통해 안전하게 처리할 수 있다.
var someWindow: NSWindow? // 옵셔널로 선언
func closeAlarmWindow() {
SoundSetting.instance.onStopSound()
if let window = someWindow {
window.close()
} else {
print("Window is nil, cannot close it.")
}
}
요약:
NSWindow!
타입은 강제 언래핑을 사용하므로 안전하게 접근하려면 옵셔널 바인딩(if let
)을 사용하는 것이 좋다.nil
체크 후 안전하게 값을 처리하도록 하여 런타임 오류를 방지한다.- 가능하다면
NSWindow?
와 같은 일반 옵셔널 타입으로 변경하는 것도 좋은 선택이다.
이렇게 수정하면 nil
값에 의한 오류를 방지할 수 있다.