programing

'치명적 오류:Optional value'의 래핑을 해제하는 동안 예기치 않게 0이 발견되었습니까?

elecom 2023. 4. 13. 20:32
반응형

'치명적 오류:Optional value'의 래핑을 해제하는 동안 예기치 않게 0이 발견되었습니까?

은 「」와 충돌하고 있다.EXC_BAD_INSTRUCTION및 다음과 같은 유사한 오류 중 하나가 있습니다.이 오류의 의미와 수정 방법은 무엇입니까?

치명적인 오류:옵션 값을 언랩하는 동안 예기치 않게 0이 발견되었습니다.

또는

치명적인 오류:옵션 값을 암묵적으로 언랩하는 동안 예기치 않게 0을 찾았습니다.


이 투고는, 「예상치 않은 제로」의 문제에 대한 회답을 수집해, 문제가 산재해 있어 찾기 어려운 상태가 되지 않게 하는 것을 목적으로 하고 있습니다.원하는 답변을 추가하거나 기존 Wiki 답변을 편집하십시오.

배경:옵션이란?

Swift 에서는, 는 옵션 타입입니다.원래("랩핑"타입의 임의의 값을 포함할 수도 있고, 값이 전혀 포함되지 않을 수도 있습니다(특수값).nil옵션 값을 사용하려면 먼저 래핑을 해제해야 합니다.

옵션은 범용 타입입니다.즉,Optional<Int> ★★★★★★★★★★★★★★★★★」Optional<String> 유형: " 유형: " " "<>는 랩 타입이라고 불립니다.후드 아래에 있는 Optional은 다음 두 가지 경우를 포함하는 열거형입니다..some(Wrapped) ★★★★★★★★★★★★★★★★★」.none서, snowledge..none nil.

에는, 붙여진 할 수 있습니다.Optional<T> (로서 「」(「」)을 합니다.?서픽스

var anInt: Int = 42
var anOptionalInt: Int? = 42
var anotherOptionalInt: Int?  // `nil` is the default when no value is provided
var aVerboseOptionalInt: Optional<Int>  // equivalent to `Int?`

anOptionalInt = nil // now this variable contains nil instead of an integer

옵션이란 코드를 작성할 때 가정사항을 표현할 수 있는 간단하면서도 강력한 도구입니다.컴파일러는 이 정보를 사용하여 실수를 방지할 수 있습니다.Swift 프로그래밍 언어:

Swift는 타입 세이프 언어입니다.즉, 이 언어는 코드를 사용할 수 있는 값의 유형을 명확하게 하는 데 도움이 됩니다.코드의 일부가 필요한 경우String할 수 Int잘못해서마찬가지로 type safety를 사용하면 옵션이 아닌 것을 필요로 하는 코드에 실수로 옵션을 전달하는 것을 방지할 수 있습니다.Type Safety는 개발 프로세스에서 오류를 가능한 한 빨리 발견하고 수정하는 데 도움이 됩니다.

일부 다른 프로그래밍 언어에도 일반적인 옵션 유형이 있습니다. 예를 들어 Maybe in Haskell, option in Rust, optional in C++17 입니다.

옵션 타입이 없는 프로그래밍 언어에서는 유효한 값이 없음을 나타내기 위해 특정 "sentinel" 값이 자주 사용됩니다.예를 들어 Objective-C에서는nil( 포인터)는 객체가 없음을 나타냅니다.다음과 같은 원시 유형의 경우int, 늘수 없기 에, 변수를 들면, null 「」등)가value: Int ★★★★★★★★★★★★★★★★★」isValid: Bool값('sentinel' 등)을 지정합니다-1 ★★★★★★★★★★★★★★★★★」INT_MIN)isValid또는 Sentinel 값을 확인합니다.또한 특정 값이 Sentinel로 선택되면 더 이상 유효한 값으로 취급할 수 없습니다.

Swift Swift 의 Optional 별개로 nil 값을 ) 및 컴파일러가 을 기억하도록 가 도울 수 으로써 값(sentinel 값 지정 불필요)을 설정합니다.value ( sentinel 값)는 0입니다.


'치명적 오류: 옵션 값을 언랩할예기치 않게 0이 검출되었습니다.

옵션의 값(있는 경우)에 액세스 하려면 , 옵션의 값을 언랩 할 필요가 있습니다.옵션 값은 안전하게 또는 강제로 풀 수 있습니다.옵션에서 강제로 래핑을 풀었을 때 값이 없으면 위의 메시지와 함께 프로그램이 크래시됩니다.

Xcode는 코드 행을 강조 표시하여 크래시를 표시합니다.이 회선에서 문제가 발생.

크래시 라인

이 크래시는 다음 2종류의 강제 언랩으로 발생할 수 있습니다.

1. 명시적인 힘 풀기

해서 하는 예요.!연산자를 선택합니다.예를 들어 다음과 같습니다.

let anOptionalString: String?
print(anOptionalString!) // <- CRASH

치명적인 오류:옵션 값을 언랩하는 동안 예기치 않게 0이 발견되었습니다.

~로anOptionalStringnil여기서 강제로 포장을 뜯는 선에서 충돌이 발생할 것입니다.

2. 암묵적으로 포장되지 않은 옵션

은 「」로 됩니다.! 게 아니라.?활자 뒤에.

var optionalDouble: Double!   // this value is implicitly unwrapped wherever it's used

이러한 옵션에는 값이 포함되어 있는 것으로 간주됩니다.따라서 암묵적으로 래핑 해제된 옵션에 액세스할 때마다 자동으로 래핑이 해제된 옵션은 자동으로 래핑 해제됩니다.값이 포함되지 않으면 크래시됩니다.

print(optionalDouble) // <- CRASH

치명적인 오류:옵션 값을 암묵적으로 언랩하는 동안 예기치 않게 0을 찾았습니다.

크래시의 원인이 된 변수를 확인하려면 , 를 클릭해 정의를 표시합니다.선택적인 타입을 찾을 수 있습니다.

특히 IBOutlet은 일반적으로 암묵적으로 포장되지 않은 옵션입니다.이는 초기화 후 실행 시 xib 또는 스토리보드가 콘센트를 연결하기 때문입니다.따라서 콘센트가 로딩되기 전에 콘센트에 액세스하지 않도록 해야 합니다.또한 스토리보드/xib 파일에서 연결이 올바른지 확인해야 합니다. 그렇지 않으면 값이 다음과 같습니다.nil따라서 암시적으로 래핑이 해제되면 크래시됩니다.연결을 수정할 때 콘센트를 정의하는 코드 행을 삭제한 후 다시 연결하십시오.


옵션 포장은 언제 풀어야 합니까?

명시적 강제 언랩

「」를 하지 말아 .!하다, 사용하다, 사용하다, 사용하다, 하다, 사용하다, 사용하다, 사용하다, 사용하다, 하다, 사용하다, 사용하다, 사용하다, 사용하다, 사용하다, 사용하다, 사용하다, 사용하다, 사용하다.!는 허용됩니다.다만, 옵션의 값이 포함되어 있는 것이 100% 확실한 경우에만, 이 값을 사용해 주세요.

옵션에는 값이 포함되어 있는 을 알 수 있듯이 강제 개봉을 사용할 수 있는 경우가 있습니다만, 그 대신 안전하게 개봉할 수 있는 곳은 없습니다.

암묵적으로 언랩된 옵션

이러한 변수는 코드 후반까지 할당을 연기할 수 있도록 설계되었습니다.액세스 하기 전에, 유저가 가치를 가지는 것을 확인하는 것은, 유저의 책임입니다.그러나 강제 해제를 수반하기 때문에 0 할당은 유효하지만 값이 nil이 아닌 것으로 간주하기 때문에 본질적으로 안전하지 않습니다.

마지막 수단으로 암묵적으로 포장되지 않은 옵션만 사용해야 합니다.레이지 변수를 사용할 수 있는 경우 또는 변수의 기본값을 지정할 수 있는 경우 암묵적으로 래핑 해제된 옵션을 사용하는 대신 이 옵션을 사용해야 합니다.

단, 암묵적으로 포장을 해제한 옵션이 도움이 되는 경우가 몇 가지 있습니다.또, 다음과 같이 안전하게 포장을 해제할 수 있는 다양한 방법도 있습니다만, 항상 충분히 주의해 주세요.


Optionals를 안전하게 취급하려면 어떻게 해야 합니까?

값이 되어 있는지 은 값이 되어 있는지 입니다.nil.

if anOptionalInt != nil {
    print("Contains a value!")
} else {
    print("Doesn’t contain a value.")
}

그러나 옵션 사용 시 99.9%가 포함된 값에 실제로 액세스해야 합니다.이를 위해 옵션 바인딩을 사용할 수 있습니다.

옵션 바인딩

[ Optional Binding ]를 사용하면 옵션의 값이 포함되어 있는지 여부를 확인할 수 있습니다.또, 래핑 해제된 값을 새로운 변수 또는 상수에 할당할 수 있습니다. 구문을 요.if let x = anOptional {...} ★★★★★★★★★★★★★★★★★」if var x = anOptional {...}(바인딩 후 새 변수 값을 변경해야 하는지 여부에 따라 달라집니다.

예를 들어 다음과 같습니다.

if let number = anOptionalInt {
    print("Contains a value! It is \(number)!")
} else {
    print("Doesn’t contain a number")
}

이 작업은 우선 옵션에 값이 포함되어 있는지 확인합니다.경우, "unwraped" 값이 새 변수에 할당됩니다( unwraped).number( ) – 옵션 이외의 것처럼 자유롭게 사용할 수 있습니다.옵션에 값이 포함되지 않은 경우 예상대로 else 구가 호출됩니다.

옵션 바인딩의 장점은 여러 옵션을 동시에 풀 수 있다는 것입니다.명령문은 쉼표로 구분하면 됩니다.이 문장은 모든 옵션의 포장을 해제하면 성공합니다.

var anOptionalInt : Int?
var anOptionalString : String?

if let number = anOptionalInt, let text = anOptionalString {
    print("anOptionalInt contains a value: \(number). And so does anOptionalString, it’s: \(text)")
} else {
    print("One or more of the optionals don’t contain a value")
}

또 하나의 깔끔한 트릭은 값을 언랩한 후 쉼표를 사용하여 값의 특정 조건을 확인할 수도 있다는 것입니다.

if let number = anOptionalInt, number > 0 {
    print("anOptionalInt contains a value: \(number), and it’s greater than zero!")
}

if 스테이트먼트 내에서 옵션바인딩을 사용할 때의 유일한 단점은 스테이트먼트의 범위 내에서만 래핑되지 않은 값에 액세스할 수 있다는 것입니다.문의 범위 밖에서 값에 액세스해야 할 경우 guard 문을 사용할 수 있습니다.

guard 문을 사용하면 성공 조건을 정의할 수 있습니다.현재 스코프는 해당 조건이 충족된 경우에만 실행을 계속합니다.이들은 다음 구문을 사용하여 정의됩니다.guard condition else {...}.

따라서 이들을 옵션바인딩과 함께 사용하려면 다음 작업을 수행합니다.

guard let number = anOptionalInt else {
    return
}

(가드 본체 내에서 현재 실행 중인 코드의 범위를 종료하려면 control transfer 스테이트먼트 중 하나를 사용해야 합니다).

ifanOptionalInt 래핑이 됩니다.이 값은 래핑 해제되어 새 값에 할당됩니다.number일정한.그런 다음 가드 뒤의 코드가 계속 실행됩니다.값이 포함되지 않은 경우 – 가드는 대괄호 내에서 코드를 실행하며, 이로 인해 제어가 전송되므로 직후 코드가 실행되지 않습니다.

guard 스테이트먼트의 진정한 장점은 랩 해제된 값을 스테이트먼트 뒤에 이어지는 코드에서 사용할 수 있다는 것입니다(옵션에 값이 있는 경우에만 미래 코드를 실행할 수 있습니다).이는 여러 if 문을 중첩하여 생성되는 '운명의 피라미드'를 제거하는 데 매우 유용합니다.

예를 들어 다음과 같습니다.

guard let number = anOptionalInt else {
    return
}

print("anOptionalInt contains a value, and it’s: \(number)!")

가드는 지원했던 를 들어, 복수의 의 래핑을 하거나, 「」의 경우는 「」를 사용합니다.예를 들어 여러 옵션의 동시 개봉과where절을 클릭합니다.

if 문과 guard 문 중 어느 쪽을 완전히 사용할지는 미래의 코드에 값을 포함하기 위해 옵션이 필요한지 여부에 따라 달라집니다.

병합 연산자 없음

Nil Coalescing 연산자는 주로 옵션을 비옵션으로 변환하도록 설계된 3진수 조건부 연산자의 간략한 버전입니다.그것은 구문을 가지고 있다.a ?? b서, snowledge.a으로, 는 옵션 타입입니다.b입니다.a(예: , ( 、 ( ( ( ( ( ( ().

'만약에'라고 '에 '만약에'라고 하면 . '아쉬운'a값이 포함되어 있으므로 래핑을 해제하십시오.않으면 돌아오세요.b 다음과같이 할 수 .예를 들어 다음과 같이 사용할 수 있습니다.

let number = anOptionalInt ?? 0

하면 이이 a a a a a a가 됩니다.number of의 입니다.Int값 중 합니다.anOptionalInt되어 있는 또는 「」를 참조해 주세요0렇지지그

그냥 줄임말이에요.

let number = anOptionalInt != nil ? anOptionalInt! : 0

체인(옵션)

옵션 체인을 사용하여 메서드를 호출하거나 옵션의 속성에 액세스할 수 있습니다.이것은 단순히 변수 이름에 접미사를 붙이면 됩니다.?사용할 때 사용합니다.

들어 요?foo)을 합니다.Foo★★★★★★ 。

var foo : Foo?

를 들어 ''를 foo이치노을 사용하다

foo?.doSomethingInteresting()

iffoo값이 포함되어 있기 때문에 이 메서드가 호출됩니다.그렇지 않은 경우, 나쁜 일은 발생하지 않습니다.코드는 계속 실행됩니다.

(은, ( 「 」 , 「 」 )에 nil표표-C)에서

이 때문에, 속성이나 콜 방식 설정에도 사용할 수 있습니다.예를 들어 다음과 같습니다.

foo?.bar = Bar()

말하지만, 여기서 것입니다.foonil코드 실행은 계속됩니다.

옵션 체인을 통해 수행할 수 있는 또 다른 간단한 방법은 속성 설정 또는 메서드 호출이 성공했는지 확인하는 것입니다.을 ""에 합니다.nil.

입니다).Void?Void★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」

예를 들어 다음과 같습니다.

if (foo?.bar = Bar()) != nil {
    print("bar was set successfully")
} else {
    print("bar wasn’t set successfully")
}

단, 값을 반환하는 속성이나 호출 메서드에 액세스하려고 하면 조금 더 까다로워집니다. ★★★★★★★★★★★★★★★★★★foo이 옵션에서 반환되는 모든 항목도 옵션입니다. 중 하거나 래핑을 합니다.foo값을 반환하는 메서드 또는 호출 메서드에 액세스하기 전에 그 자체입니다.

또한 이름에서 알 수 있듯이 이러한 문장을 함께 '체인'할 수 있습니다., ,, 약의 foo 속성이 .baz있다qux 쓸 수 - 이렇게 쓸 수 있어요.

let optionalQux = foo?.baz?.qux

한 번 말씀드리지만, 왜냐하면foo ★★★★★★★★★★★★★★★★★」baz ""에서 값"" ""에서 반환된 값"qux는 반드시 선택 사항입니다.qux을 사용하다

map ★★★★★★★★★★★★★★★★★」flatMap

에서 자주 되지 않는 입니다.map ★★★★★★★★★★★★★★★★★」flatMap 할 수 .이를 통해 옵션 변수가 아닌 변환을 적용할 수 있습니다.옵션의 값이 있는 경우 지정된 변환을 적용할 수 있습니다..nil.

예를 들어 다음과 같은 옵션 문자열이 있다고 가정합니다.

let anOptionalString:String?

「 」를 하면,map기능 – 를 사용할 수 있습니다.stringByAppendingString다른 문자열에 연결하기 위한 함수입니다.

★★★★★★★★★★★★★★★★★★stringByAppendingString는 비옵션 문자열 인수를 사용합니다.옵션 문자열을 직접 입력할 수 없습니다. 「」를 하는 것으로 합니다.map는 allow를 할 수 stringByAppendingStringanOptionalString치가있있 있있있다다

예를 들어 다음과 같습니다.

var anOptionalString:String? = "bar"

anOptionalString = anOptionalString.map {unwrappedString in
    return "foo".stringByAppendingString(unwrappedString)
}

print(anOptionalString) // Optional("foobar")

「」의 경우는, 「」입니다.anOptionalStringmapnil §:

var anOptionalString:String?

anOptionalString = anOptionalString.map {unwrappedString in
    return "foo".stringByAppendingString(unwrappedString)
}

print(anOptionalString) // nil

flatMap와 마찬가지로 동작하다map단, 클로저 본문 내에서 다른 옵션을 반환할 수 있습니다.즉, 옵션 이외의 입력이 필요한 프로세스에 옵션을 입력할 수 있지만 옵션 자체를 출력할 수 있습니다.

try!

Swift의 오류 처리 시스템은 Do-Try-Catch와 함께 안전하게 사용할 수 있습니다.

do {
    let result = try someThrowingFunc() 
} catch {
    print(error)
}

ifsomeThrowingFunc()됩니다.이치노catch

error에서 볼 수 있는 catch아니다.-아니다.catch.

요.error예를 들어 다음과 같은 유용한 형식으로 캐스팅할 수 있다는 장점이 있습니다.

do {
    let result = try someThrowingFunc()    
} catch let error as NSError {
    print(error.debugDescription)
}

「」를 사용합니다.try이렇게 하면 던지기 기능으로 인한 오류를 발견하고 처리할 수 있습니다.

그리고 또try?에러를 흡수합니다.

if let result = try? someThrowingFunc() {
    // cool
} else {
    // handle the failure, but there's no error information available
}

Swift의 "Swift"와 " Try"Force try"합니다.try!:

let result = try! someThrowingFunc()

이 투고에서는, 에러가 발생했을 경우, 애플리케이션이 크래쉬 하는 개념도 여기에 적용됩니다.

항상 사용하셔야 합니다.try!그 결과가 당신의 맥락에서 결코 실패하지 않는다는 것을 증명할 수 있다면, 이것은 매우 드문 일입니다.

인 Do-Try-Catch 시스템을 합니다.try?에러 처리가 중요하지 않은 경우는 거의 없습니다.


자원.

TL;DR 응답

극히 소수의 예외를 제외하고 이 규칙은 황금입니다.

을 피하다!

를 옵션 「」 「」 「」)으로 선언합니다.?IUOIUO)이 아닙니다!)

말하면, ,, 음, 음, 음, 음, 음, 음, 다, 다, 다, 다, 다 다, 다를 사용합니다.
var nameOfDaughter: String?

★★★★
var nameOfDaughter: String!

를 사용하여 옵션 .if let ★★★★★★★★★★★★★★★★★」guard let

다음과 같이 변수를 언랩합니다.

if let nameOfDaughter = nameOfDaughter {
    print("My daughters name is: \(nameOfDaughter)")
}

또는 다음과 같이 합니다.

guard let nameOfDaughter = nameOfDaughter else { return }
print("My daughters name is: \(nameOfDaughter)")

답변은 전체 이해도를 높이기 위해 간결하게 작성되었습니다.


자원.

질문은 SO에서 항상 언급된다.이것은 새로운 Swift 개발자들이 가장 먼저 어려움을 겪는 것 중 하나입니다.

배경:

Swift는 "옵션" 개념을 사용하여 값을 포함하거나 포함하지 않을 수 있는 값을 처리합니다.C와 같은 다른 언어에서는 변수에 값 0을 저장하여 값이 없음을 나타낼 수 있습니다.그러나 0이 유효한 값이면 어떻게 됩니까?그러면 -1을 사용할 수 있습니다.-1이 유효한 값이면 어떻게 됩니까?기타 등등.

Swift 옵션을 사용하면 유효한 값을 포함하거나 값을 포함하지 않도록 모든 유형의 변수를 설정할 수 있습니다.

변수를 평균으로 선언할 때 유형 뒤에 물음표를 붙입니다(x 또는 값 없음).

선택사항은 실제로 지정된 유형의 변수를 포함하거나 아무것도 포함하지 않는 컨테이너입니다.

값을 안으로 가져오려면 옵션에서 "랩 해제"해야 합니다.

"!" 연산자는 "force unrap" 연산자입니다.'날 믿어줘'라고 써있네난 내가 뭘 하고 있는지 안다.이 코드가 실행될 때 변수에 0이 포함되지 않음을 보증합니다."틀리면 추락한다.

실제로 무엇을 하고 있는지 모르는 경우는, 「!」라고 하는 강제 언랩 오퍼레이터는 사용하지 말아 주세요.이것은 아마도 Swift 프로그래머를 시작하는 데 가장 큰 크래시 원인일 것입니다.

옵션 처리 방법:

더 안전한 옵션들을 다루는 많은 다른 방법들이 있습니다.다음은 (전체 목록은 아님) 몇 가지입니다.

"optional binding" 또는 "if let"을 사용하여 "옵션에 값이 포함되어 있는 경우 해당 값을 새로운 비옵션 변수에 저장합니다.옵션에 값이 포함되지 않은 경우 이 if 문의 본문을 건너뜁니다."

는 우리의 입니다.foo★★★★

if let newFoo = foo //If let is called optional binding. {
  print("foo is not nil")
} else {
  print("foo is nil")
}

옵션 바이딩을 사용할 때 정의하는 변수는 if 문의 본문에만 존재합니다('범위 내'만).

또는 guard 문을 사용하여 변수가 0일 경우 함수를 종료할 수 있습니다.

func aFunc(foo: Int?) {
  guard let newFoo = input else { return }
  //For the rest of the function newFoo is a non-optional var
}

Swift 2에 가드 문구가 추가되었습니다.가드를 사용하면 코드를 통해 "골든 경로"를 보존할 수 있으며 "if let" 옵션 바인딩을 사용하여 발생하는 중첩된 if의 수준이 계속 증가하는 것을 방지할 수 있습니다.

또한 "nil cursing operator"라고 하는 구성도 있습니다.형식은 "optional_var" 입니다.replacement_val"을 클릭합니다.옵션에 포함된 데이터와 동일한 유형의 비옵션 변수를 반환합니다.옵션에 0이 포함되어 있으면 " 뒤에 식 값이 반환됩니다.?" 기호.

따라서 다음과 같은 코드를 사용할 수 있습니다.

let newFoo = foo ?? "nil" // "??" is the nil coalescing operator
print("foo = \(newFoo)")

시행/캐치 또는 가드 오류 처리를 사용할 수도 있지만 일반적으로 위의 다른 방법 중 하나가 더 깔끔합니다.

편집:

옵션에서 조금 더 미묘한 또 다른 방법은 "암묵적으로 포장되지 않은 옵션"입니다.우리가 foo를 선언할 때, 우리는 다음과 같이 말할 수 있습니다.

var foo: String!

이 경우 foo는 옵션이지만 참조하기 위해 개봉할 필요가 없습니다.즉, foo를 참조하려고 할 때마다, 0이 되면 충돌합니다.

이 코드는 다음과 같습니다.

var foo: String!


let upperFoo = foo.capitalizedString

foo의 capitalizedString 속성을 참조하여 크래시됩니다(foo를 강제로 언랩하지 않아도 됩니다).인쇄는 괜찮아 보이지만, 그렇지 않아요.

따라서 암시적으로 포장되지 않은 옵션에 대해 매우 주의해야 합니다(옵션에 대한 확실한 이해가 이루어질 때까지 완전히 피해야 합니다).

결론:Swift를 처음 배울 때는 "!"자가 언어의 일부가 아닌 것처럼 행동합니다.그것은 당신을 곤란하게 할 것 같아요.

위의 답변은 Optionals를 사용하여 안전하게 플레이하는 방법을 명확하게 설명합니다.나는 Optionals가 정말로 빠른지에 대해 설명하려고 노력할 것이다.

옵션 변수를 선언하는 다른 방법은 다음과 같습니다.

var i : Optional<Int>

Optional type은 두 가지 케이스가 포함된 열거형일 뿐입니다.

 enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none 
    case some(Wrapped)
    .
    .
    .
}

수 있다var i = Optional<Int>.none 값을 몇 값을 해 드리겠습니다.var i = Optional<Int>.some(28)

을 사용하다, 을 사용하다. and음izedizedizedized로 nil에 안 .ExpressibleByNilLiteral입니다.OptionalsExpressibleByNilLiteral다른 타입에 준거하는 것은 권장되지 않습니다.

ExpressibleByNilLiteral에는 고하하 called called called called called called called called called called called called called called called 라는 단일 방법이 있습니다.init(nilLiteral:)0의 설치하다이. 신속한 을 "Optional"로하므로 이 호출하는 되지 않습니다.또한 빠른 설명서에 따르면 컴파일러가 이 이니셜라이저를 호출할 때마다 직접 호출하는 것은 권장되지 않습니다.nil문자 그대로의

나 자신도 Optionals:D Happy Swfting All에 머리를 싸매야 합니다.

우선 Optional 값이 무엇인지 알아야 합니다.자세한 내용은 Swift Programming Language를 참조하십시오.

둘째, 옵션 값에는 두 가지 상태가 있습니다.하나는 풀값이고 다른 하나는 제로값입니다.따라서 옵션 값을 구현하기 전에 해당 값이 어떤 상태인지 확인해야 합니다.

하시면 됩니다.if let ... ★★★★★★★★★★★★★★★★★」guard let ... else기타 등등.

다른 에 변수 하고 싶지 경우, '하다'를 사용할 .var buildingName = buildingName ?? "buildingName"★★★★★★ 。

prepare for segue 메서드에서 아울렛 값을 다음과 같이 설정하려고 할 때 이 오류가 발생한 적이 있습니다.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? DestinationVC{

        if let item = sender as? DataItem{
            // This line pops up the error
            destination.nameLabel.text = item.name
        }
    }
}

그 후 컨트롤러가 아직 로드되지 않았거나 초기화되지 않았기 때문에 대상 컨트롤러 콘센트의 값을 설정할 수 없다는 것을 알게 되었습니다.

그래서 이렇게 해결했습니다.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? DestinationVC{

        if let item = sender as? DataItem{
            // Created this method in the destination Controller to update its outlets after it's being initialized and loaded
            destination.updateView(itemData:  item)
        }
    }
}

수신처 컨트롤러:

// This variable to hold the data received to update the Label text after the VIEW DID LOAD
var name = ""

// Outlets
@IBOutlet weak var nameLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    nameLabel.text = name
}

func updateView(itemDate: ObjectModel) {
    name = itemDate.name
}

저는 이 답변이 옵션과 그 작동 방식을 이해하는 데 도움이 되지만 문제 자체에 직접 대처하지는 않았다는 것을 알게 된 것과 같은 문제를 가지고 있는 모든 사람에게 도움이 되기를 바랍니다.

기본적으로 Swift가 null이 아닌 값만 허용하는 곳에서는 null 값을 사용하려고 했고, 컴파일러에게 null 값은 존재하지 않는다고 말함으로써 앱 컴파일을 허용했습니다.

다음과 같은 치명적인 오류가 발생하는 몇 가지 시나리오가 있습니다.

  1. 강제 압축 해제:

    let user = someVariable!
    

    ifsomeVariable0이 되면 추락할 거야강제 언랩을 실행함으로써 제로 체크의 책임을 컴파일러에서 사용자에게 이전하고 기본적으로 강제 언랩을 실행함으로써 컴파일러에 제로 값이 없음을 보증합니다. 어떤 이 0으로 끝나면 해 보세요.someVariable

    해결책?옵션 바인딩(일명 if-let)을 사용하여 변수 처리를 수행합니다.

    if user = someVariable {
        // do your stuff
    }
    
  2. 강제(다운):

    let myRectangle = someShape as! Rectangle
    

    여기서 강제 캐스팅에 의해 컴파일러에게 더 이상 걱정하지 말라고 말합니다.항상 당신이 가지고 있는 것은Rectangle이치노그리고 그게 지속되는 한, 당신은 걱정할 필요가 없어.이 문제는 사용자 또는 프로젝트의 동료가 직각 이외의 값을 순환하기 시작할 때 시작됩니다.

    해결책?옵션 바인딩(일명 if-let)을 사용하여 변수 처리를 수행합니다.

    if let myRectangle = someShape as? Rectangle {
        // yay, I have a rectangle
    }
    
  3. 암시적으로 패키지 해제된 옵션입니다.다음과 같은 클래스 정의가 있다고 가정합니다.

    class User {
        var name: String!
    
        init() {
            name = "(unnamed)"
        }
    
        func nicerName() {
            return "Mr/Ms " + name
        }
    }
    

    이제 아무도 , 아무도 망치지 않습니다.name(「」로 )nil 건데, 에 ,, ,, ,, 니, ,, ,, ,, ,, ,, ,, ,, ,, User는 JSON이 됩니다.name키를 누르면 속성을 사용하려고 할 때 치명적인 오류가 발생합니다.

    해결책?사용하지 마십시오:) 102%가 속성을 사용해야 할 때까지 항상 nil이 아닌 값을 가질 것이라고 확신하지 않는 한.대부분의 경우 옵션 또는 비옵션으로 변환됩니다.이것을 옵션 이외의 것으로 하면, 컴파일러가 그 속성에 값을 부여하지 않은 코드 패스를 통지하는 것에 의해서도 도움이 됩니다.

  4. 미접속 또는 미접속 콘센트.이것은 시나리오 #3의 특정 경우입니다.기본적으로 사용하는 XIB 로드 클래스가 있습니다.

    class SignInViewController: UIViewController {
    
        @IBOutlet var emailTextField: UITextField!
    }
    

    XIB 에디터에서 콘센트를 연결하지 못한 경우 콘센트를 사용하는 즉시 앱이 크래시됩니다.모두 되어 있는지 합니다.모든 콘센트가 접속되어 있는 것을 확인합니다. '아까보다'를 하세요.? operator: 연 operator:emailTextField?.text = "my@email.com"또는 콘센트를 옵션이라고 선언합니다만, 이 경우는 컴파일러에 의해서 모든 코드에서 언랩이 강제됩니다.

  5. Objective-C에서 가져온 값으로, nullability 주석이 없습니다.다음과 같은 Objective-C 클래스가 있다고 가정합니다.

    @interface MyUser: NSObject
    @property NSString *name;
    @end
    

    되지 않은 nullability를 통해)NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_ENDname에서 "Swift" Import"로 .String!(IUO - 묵 ( ( ( ( ( ( ( ( ( ( ()..name0입니다.

    ? 코드에 합니다.Objective-C는 무효입니다., 컴파일러는합니다.Objective-C 이 될 수 nonnull.

, 왜 이 디버깅에 일 수 알 수 .nil★★★★★★ 。

다음 코드를 생각해 보겠습니다.오류/경고 없이 컴파일:

c1.address.city = c3.address.city

그러나 실행 시 다음과 같은 오류가 발생합니다. Fatal error: 옵션 값을 언랩하는 동안 예기치 않게 0이 발견되었습니다.

인지 알 수요?nil

할 수 없습니다!

전체 코드는 다음과 같습니다.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var c1 = NormalContact()
        let c3 = BadContact()

        c1.address.city = c3.address.city // compiler hides the truth from you and then you sudden get a crash
    }
}

struct NormalContact {
    var address : Address = Address(city: "defaultCity")
}

struct BadContact {
    var address : Address!
}

struct Address {
    var city : String
}

하자면 단히말,, using using를 해서,var address : Address!당신은 변수가 다른 사람에게 영향을 미칠 가능성을 숨기고 있습니다.nil뭇매를 맞다그리고 그게 충돌할 때 넌 "뭐야!"의 것address선택사항이 아닌데 왜 난 크래쉬 하는 거야?!

따라서 다음과 같이 쓰는 것이 좋습니다.

c1.address.city = c2.address!.city  // ERROR:  Fatal error: Unexpectedly found nil while unwrapping an Optional value 

어떤 인지 알 수요?nil

이치노'그럴 것 같다'라고 할 수 요.address이치노

전체 코드는 다음과 같습니다.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var c1 = NormalContact()
        let c2 = GoodContact()

        c1.address.city = c2.address!.city
        c1.address.city = c2.address?.city // not compile-able. No deceiving by the compiler
        c1.address.city = c2.address.city // not compile-able. No deceiving by the compiler
        if let city = c2.address?.city {  // safest approach. But that's not what I'm talking about here. 
            c1.address.city = city
        }

    }
}

struct NormalContact {
    var address : Address = Address(city: "defaultCity")
}

struct GoodContact {
    var address : Address?
}

struct Address {
    var city : String
}

입니다.EXC_BAD_INSTRUCTION ★★★★★★★★★★★★★★★★★」fatal error: unexpectedly found nil while implicitly unwrapping an Optional value되는 것은 appears an appears appears appears an an an 。@IBOutlet, 그러나 스토리보드에 연결되어 있지 않습니다.

다른 답변에서 언급된 옵션 작동 방식도 알아야 합니다. 하지만 이 시간에만 가장 많이 나타납니다.

CollectionView에서 이 오류가 발생하면 CustomCell 파일과 Custom xib도 만들어 보십시오.

이 코드를 mainVC의 ViewDidLoad()에 추가합니다.

    let nib = UINib(nibName: "CustomnibName", bundle: nil)
    self.collectionView.register(nib, forCellWithReuseIdentifier: "cell")

Xcode 12 iOS 14 Swift 5

스토리보드를 인스턴스화하지 않고 vie 컨트롤러를 직접 호출했기 때문에 스토리보드에서 아직 데이터가 설정되지 않은 것이 문제였습니다.

탐색할 때 다음을 사용하여 탐색합니다.

let homeViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "home") as? HomeEventsViewController
    homeViewController?.modalTransitionStyle = .crossDissolve
    homeViewController?.modalPresentationStyle = .fullScreen
    view.present(homeViewController ?? UIViewController(), animated: true, completion: nil)

기능하기를 바란다:-)

메인 스토리보드에서 뷰 컨트롤러의 커스텀클래스 이름을 지정하는 것을 잊어버렸기 때문에 테이블 뷰 컨트롤러에서 뷰 컨트롤러로 segue를 작성할 때 이 오류가 발생했습니다.

다른 모든 것이 정상으로 보이는지 확인할 가치가 있는 간단한 것

내 경우 변수를 0으로 UILabel로 설정했을 경우.

그래서 고쳤더니 오류가 안 나더라고요.

코드 스니펫

class ResultViewController: UIViewController {

    @IBOutlet weak var resultLabel: UILabel!
    var bmiValue=""
    override func viewDidLoad() {
        super.viewDidLoad()
        print(bmiValue)
        resultLabel.text=bmiValue //where bmiValue was nil , I fixed it and problem was solved

    }
    
    @IBAction func recaculateBmi(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
    

}

사용할 수 .guard ★★★★★★★★★★★★★★★★★」if let!variable(의

Swift 5.7 이상

if let a variable의

위의 답변은 이 문제가 발생하는 이유와 이 문제를 처리하는 방법을 명확하게 설명합니다.하지만 이 문제를 해결하는 새로운 방법이 있습니다.swift 5.7+그 이후로는.

var myVariable : Int?

이전에.

if let myVariable = myVariable {
    //this part get executed if the variable is not nil
}else{
    //this part get executed if the variable is nil
}

지금이다

여기서는 오른쪽을 생략할 수 있습니다.

if let myVariable {
    //this part get executed if the variable is not nil
}else{
    //this part get executed if the variable is nil
}

이전에는 참조된 식별자를 두 번 반복해야 했습니다.이 때문에 특히 긴 변수 이름을 사용할 경우 이러한 옵션의 바인딩 조건이 상세해질 수 있습니다.

단, 이 경우 표현의 오른쪽을 생략하여 옵션바인딩을 위한 약어 구문이 있습니다.

입니다.guard let★★★★★★ 。

상세한 것에 대하여는, 다음을 참조해 주세요.

if-let 속기 제안

이는 0이 될 수 있는 값을 사용하려고 하지만 체크할 필요가 없다고 판단했기 때문입니다.대신 사용할 때 그 집합을 가정하고!로 정의하기 때문입니다.변수 집합을 강제 언랩으로 사용하는 것에는 다른 철학이 있으며, 일부 사람들은 아예 사용을 반대합니다.항상 크래시 되는 문제에는 문제가 없고, 일반적으로 리소스를 참조하거나, xib 파일에 대한 아웃렛이나, 자산의 일부인 앱과 함께 이미지를 사용하는 등의 간단한 이유에도 문제가 없다고 생각합니다.이것들이 올바르게 설정되어 있지 않으면 앱은 즉시 크래시 됩니다.명백한 이유로 인해 크래시 됩니다.생성되는 객체의 순서가 불분명할 수 있고 이에 대한 해결책을 추론하는 것은 어려울 수 있습니다.이는 보통 설계를 잘못했다는 것을 의미합니다.옵션 변수를 호출해도 실행되지 않을 수 있으며, 일부 프로젝트에서는 보안상의 이유로 강제 해제를 요구할 수 있습니다.은행 앱과 같은 것들이 있습니다. 왜냐하면 그들은 앱이 계획되지 않은 방식으로 계속 작동하기 보다는 크래쉬하기를 원하기 때문입니다.

다른 답은 너무 길어서...

null 가능한 객체가 존재함을 알면 됩니다.또한 값("nil")을 가질 수 없습니다.오류는 값이 0인 순간에 변수 값을 가져오려고 하지만 값을 가져오려는 것은 아닙니다.

코드 라인에서 이 에러는 확실히 「이 늘 수 있는 값이 0이 아닌 것을 보증합니다.그냥 사용하세요」라고 하는 의미입니다.

이 문제를 회피하는 방법:

  1. 사용방법
// get someClassParam in case of someNullableClassInstance is not nil
let a = someNullableClassInstance?.someClassParam
  1. 내부에 값이 있는지 확인합니다.
if let someNullableClassInstance = someNullableClassInstance {
    //here is someNullableClassInstance for sure is not nil
}

//or

// this works the same as previous "if" code
if let someNullableClassInstance {
    //here is someNullableClassInstance for sure is not nil
}

//or

guard let someNullableClassInstance = someNullableClassInstance else { return }
//from this string someNullableClassInstance IS NOT NULLABLE!

//or

// this works the same as previous "guard" code
guard let someNullableClassInstance else { return }
//from this string someNullableClassInstance IS NOT NULLABLE!
  1. 기본값 사용:
// ?? means "assign value in case of nil"
let someBoolParam = someNullableClassInstance?.someBoolParam ?? false

그리고 기억하라: "!"를 사용하는 것은 정말 나쁜 관행이다.

언급URL : https://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu

반응형