SwiftUI프로그래밍

[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 정보와 같은 정보를 확인하는 방법


위 오류가 예전에 한번 발생되어 처리하였는데, 또 발생되어네..

예전 처리기록 : [SwiftUI 오류] Swift runtime failure: Unexpectedly found nil while implicitly unwrapping an Optional value + 0 (:0) 오류 해결 하는 방법

오류 메시지를 보면 “Unexpectedly found nil while implicitly unwrapping an Optional value”라는 메시지가 있다. 이는 Swift에서 옵셔널 값을 강제로 언래핑하려고 시도했을 때, 해당 값이 nil인 경우 발생하는 오류이다. 해당 오류가 발생한 위치는 CheckBattery.closeAlarmWindow() 메서드의 CheckBattery.swift:261에서 발생한 것 같다.


해결 방법

  1. 옵셔널 강제 언래핑 제거: 강제로 언래핑되는 옵셔널 값을 안전하게 처리하려면 옵셔널 바인딩(if let 또는 guard let)을 사용해야 한다.예를 들어, 코드에서 closeAlarmWindow() 메서드에서 옵셔널을 강제 언래핑하고 있는 부분을 찾아서 수정해야 한다.
// 강제 언래핑 예시
let alarmWindow = someOptionalValue!

이를 옵셔널 바인딩을 통해 안전하게 처리하면:

// 옵셔널 바인딩 예시
if let alarmWindow = someOptionalValue {
    // alarmWindow 사용
} else {
    // nil일 경우 처리
}

2. 문제 발생 지점 확인: CheckBattery.swift:261CheckBattery.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()
        }
    }

문제는 someWindowNSWindow! 타입으로 선언되어 있기 때문에, nil 값이 할당되었을 때 강제로 언래핑을 시도하는 것이다. 옵셔널 타입이 nil일 때 강제로 언래핑을 시도하면 런타임 오류가 발생한다. 그래서 if (someWindow != nil)nil 체크를 하고 있긴 하지만, 이 코드에서 여전히 문제가 발생할 수 있다.


해결 방법 1: 옵셔널 바인딩 사용

someWindow가 옵셔널이기 때문에, 이를 안전하게 처리하기 위해 옵셔널 바인딩을 사용할 수 있다. if let을 사용하여 someWindownil이 아닌 경우에만 접근하도록 변경할 수 있다.

수정된 코드:

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?와 같이 일반 옵셔널로 선언하는 것이 좋을 수 있다.
  • 예를 들어 someWindowNSWindow?로 선언하면, nil 체크를 통해 안전하게 처리할 수 있다.

var someWindow: NSWindow?  // 옵셔널로 선언

func closeAlarmWindow() {
    SoundSetting.instance.onStopSound()
    
    if let window = someWindow {
        window.close()
    } else {
        print("Window is nil, cannot close it.")
    }
}


요약:

  1. NSWindow! 타입은 강제 언래핑을 사용하므로 안전하게 접근하려면 옵셔널 바인딩(if let)을 사용하는 것이 좋다.
  2. nil 체크 후 안전하게 값을 처리하도록 하여 런타임 오류를 방지한다.
  3. 가능하다면 NSWindow?와 같은 일반 옵셔널 타입으로 변경하는 것도 좋은 선택이다.

이렇게 수정하면 nil 값에 의한 오류를 방지할 수 있다.

error: Content is protected !!