Что означает "фатальная ошибка: неожиданно найден ноль при развертывании необязательного значения"?

Моя программа Swift не работает с EXC_BAD_INSTRUCTION и эта ошибка. Что это значит, и как мне это исправить?

фатальная ошибка: неожиданно найден ноль при развертывании необязательного значения


Этот пост предназначен для сбора ответов на "неожиданно найденные ноль" проблемы, поэтому они не разбросаны и их трудно найти. Не стесняйтесь добавлять свой собственный ответ или редактировать существующий вики-ответ.

21 ответ

Решение

Этот ответ вики сообщества. Если вы чувствуете, что это может быть сделано лучше, не стесняйтесь редактировать это!

Фон: что необязательно?

В Свифте Optional является универсальным типом, который может содержать значение (любого типа) или вообще не иметь значения.

Во многих других языках программирования определенное значение "страж" часто используется для указания на отсутствие значения. В Objective-C, например, nil ( нулевой указатель) указывает на отсутствие объекта. Но это становится сложнее при работе с примитивными типами - следует -1 использоваться для указания на отсутствие целого числа или, возможно, INT_MIN или другое целое число? Если какое-либо конкретное значение выбрано для обозначения "нет целого числа", это означает, что оно больше не может рассматриваться как допустимое значение.

Swift - это типобезопасный язык, который означает, что он поможет вам понять типы значений, с которыми может работать ваш код. Если часть вашего кода ожидает строку, тип безопасности не позволяет вам передать ему Int по ошибке.

В Swift любой тип можно сделать необязательным. Необязательное значение может принимать любое значение из исходного типа или специальное значение nil,

Необязательные определяются с помощью ? суффикс по типу:

var anInt: Int = 42
var anOptionalInt: Int? = 42
var anotherOptionalInt: Int?    // `nil` is the default when no value is provided

Отсутствие значения в необязательном порядке указывается nil:

anOptionalInt = nil

(Обратите внимание, что это nil это не то же самое, что nil в Objective-C. В Objective-C, nil отсутствие действительного указателя на объект; в Swift дополнительные функции не ограничиваются объектами / ссылочными типами. Необязательный ведет себя подобно Haskell's Maybe.)


Почему я получил " фатальную ошибку: неожиданно обнаружил ноль при развертывании необязательного значения "?

Чтобы получить доступ к необязательному значению (если оно вообще есть), вам нужно развернуть его. Необязательное значение может быть развернуто безопасно или принудительно. Если вы принудительно развернете необязательный параметр, у которого не было значения, ваша программа вылетит с сообщением выше.

Xcode покажет вам сбой, выделив строку кода. Проблема возникает на этой линии.

разрушенная линия

Этот сбой может произойти с двумя различными видами принудительного развертывания:

1. Явное развертывание силы

Это сделано с ! оператор по желанию. Например:

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

Как anOptionalString является nil здесь вы получите аварию на линии, где вы заставите ее развернуть.

2. Неявно развернутые необязательные

Они определены с !, а не ? после типа.

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

Предполагается, что эти дополнительные содержат значение. Поэтому всякий раз, когда вы получаете доступ к неявно развернутому необязательному файлу, он будет автоматически развернут для вас. Если он не содержит значения, он потерпит крах.

print(optionalDouble) // <- CRASH

Чтобы определить, какая переменная вызвала сбой, вы можете удерживать , нажимая, чтобы показать определение, где вы можете найти необязательный тип.

В частности, IBOutlets обычно являются неявно развернутыми опциями. Это потому, что ваш xib или раскадровка будут связывать выходы во время выполнения после инициализации. Поэтому вы должны убедиться, что у вас нет доступа к розеткам до их загрузки. Вы также должны проверить правильность соединений в вашем файле раскадровки /xib, в противном случае значения будут nil во время выполнения, и, следовательно, сбой, когда они неявно развернуты.


Когда я должен когда-либо принудительно развернуть дополнительный?

Явная распаковка силы

Как правило, вы никогда не должны явно распаковывать опцию ! оператор. Могут быть случаи, когда использование ! Это приемлемо, но вы должны использовать его только в том случае, если вы уверены на 100%, что необязательный параметр содержит значение.

Хотя может быть случай, когда вы можете использовать принудительное развертывание, как вы знаете, для факта, что необязательный параметр содержит значение - нет ни одного места, где вы не можете безопасно развернуть это необязательное.

Неявно развернутые необязательные

Эти переменные разработаны таким образом, что вы можете отложить их назначение до следующего момента в вашем коде. Вы несете ответственность за обеспечение их ценности, прежде чем вы получите к ним доступ. Однако, поскольку они включают принудительное развертывание, они по-прежнему небезопасны - поскольку они предполагают, что ваше значение не равно нулю, даже если присвоение nil допустимо.

Вы должны использовать неявно развернутые опции только в качестве крайней меры. Если вы можете использовать переменную lazy или предоставить значение по умолчанию для переменной - вы должны сделать это вместо использования неявно развернутого необязательного параметра.

Тем не менее, есть несколько сценариев, в которых неявно распакованные опции являются полезными, и вы по-прежнему можете использовать различные способы их безопасного развертывания, как указано ниже - но вы всегда должны использовать их с должной осторожностью.


Как я могу безопасно иметь дело с Опциональными?

Самый простой способ проверить, содержит ли необязательное значение значение, - сравнить его с 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")
}

Это сначала проверяет, что необязательное содержит значение. Если это так, то значение unwrapped присваивается новой переменной (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 condition else {...},

Итак, чтобы использовать их с необязательной привязкой, вы можете сделать это:

guard let number = anOptionalInt else {
    return
}

(Обратите внимание, что внутри тела защиты вы должны использовать один из операторов передачи управления для выхода из области выполняемого в данный момент кода).

Если anOptionalInt содержит значение, оно будет развернуто и назначено новому number постоянная. Код после охраны продолжит выполнение. Если оно не содержит значения - охранник выполнит код в скобках, что приведет к передаче контроля, так что код сразу после этого не будет выполнен.

Настоящая изящная вещь в операторах guard - это то, что развернутое значение теперь доступно для использования в коде, который следует за оператором (поскольку мы знаем, что будущий код может выполняться, только если у необязательного значения есть значение). Это отлично подходит для устранения "пирамид гибели", созданных путем вложения нескольких операторов if.

Например:

guard let number = anOptionalInt else {
    return
}

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

Охранники также поддерживают те же хитрые приемы, которые поддерживал оператор if, такие как одновременное развертывание нескольких дополнительных опций и использование where пункт.

Используете ли вы оператор if или guard, полностью зависит от того, требует ли какой-либо будущий код необязательного значения.

Оператор слияния

Nil Coalescing Operator - изящная сокращенная версия троичного условного оператора, в первую очередь предназначенная для преобразования необязательных необязательных операторов. Имеет синтаксис a ?? b, где a это необязательный тип и b тот же тип, что и a (хотя обычно не является обязательным).

По сути, это позволяет вам сказать: "Если a содержит значение, разверните его. Если не вернется b вместо". Например, вы можете использовать это так:

let number = anOptionalInt ?? 0

Это определит number постоянная Int тип, который будет содержать значение anOptionalInt, если оно содержит значение, или 0 иначе.

Это просто сокращение для:

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

Опциональная цепочка

Вы можете использовать опциональное связывание, чтобы вызвать метод или получить доступ к свойству опционального. Это просто делается путем добавления суффикса к имени переменной ? при его использовании.

Например, скажем, у нас есть переменная foo типа необязательного Foo пример.

var foo : Foo?

Если бы мы хотели вызвать метод foo это ничего не возвращает, мы можем просто сделать:

foo?.doSomethingInteresting()

Если foo содержит значение, этот метод будет вызван для него. Если этого не произойдет, ничего плохого не произойдет - код просто продолжит выполнение.

(Это похоже на отправку сообщений на nil в Objective-C)

Следовательно, это также может быть использовано для установки свойств, а также для вызова методов. Например:

foo?.bar = Bar()

Опять же, ничего плохого здесь не произойдет, если foo является nil, Ваш код просто продолжит выполнение.

Еще одна хитрость, которую позволяет делать необязательное связывание, - это проверка успешности установки свойства или вызова метода. Вы можете сделать это, сравнивая возвращаемое значение с 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 мы можем использовать разрешение stringByAppendingString использоваться, если anOptionalString имеет значение.

Например:

var anOptionalString:String? = "bar"

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

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

Однако если anOptionalString не имеет значения, map вернусь nil, Например:

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)
}

Если someThrowingFunc() выдает ошибку, ошибка будет благополучно поймана в 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 также предоставляет способ "принудительной попытки" с try!:

let result = try! someThrowingFunc()

Понятия, описанные в этом посте, также применимы и здесь: если выдается ошибка, приложение вылетает.

Вы должны только когда-либо использовать try! если вы можете доказать, что его результат никогда не потерпит неудачу в вашем контексте - и это очень редко.

Большую часть времени вы будете использовать полную систему Do-Try-Catch - и дополнительную, try?, в тех редких случаях, когда обработка ошибки не важна.


Ресурсы

TL;DR ответ

За очень немногими исключениями это правило является золотым:

Избегайте использования !

Объявить переменную необязательной (?), не неявно развернутые опциональные компоненты (IUO) (!)

Другими словами, лучше использовать:
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 использует концепцию "Optionals" для работы со значениями, которые могут содержать значение или нет. В других языках, таких как C, вы можете хранить значение 0 в переменной, чтобы указать, что оно не содержит значения. Однако что, если 0 является допустимым значением? Тогда вы можете использовать -1. Что если -1 - допустимое значение? И так далее.

Опции Swift позволяют вам установить переменную любого типа, которая будет содержать либо действительное значение, либо отсутствие значения.

Вы ставите вопросительный знак после типа, когда объявляете значение переменной (тип x или нет значения).

Необязательным на самом деле является контейнер, который содержит либо переменную заданного типа, либо ничего.

Необязательный должен быть "развернут", чтобы получить значение внутри.

"!" оператор является оператором "развернуть силой". Он говорит: "Поверь мне. Я знаю, что я делаю. Я гарантирую, что при запуске этого кода переменная не будет содержать ноль". Если вы не правы, вы терпите крах.

Если вы действительно не знаете, что делаете, избегайте "!" Принудительно развернуть оператор. Это, вероятно, самый большой источник сбоев для начинающих программистов Swift.

Как бороться с опционами:

Есть много других способов иметь дело с опциями, которые безопаснее. Вот некоторые (не исчерпывающий список)

Вы можете использовать "необязательное связывание" или "если позволено", чтобы сказать "если это необязательное содержит значение, сохраните это значение в новой, необязательной переменной. Если необязательное не содержит значения, пропустите основную часть этого оператора if". ".

Вот пример необязательного связывания с нашими foo необязательный:

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

Обратите внимание, что переменная, которую вы определяете при использовании необязательного связывания, существует (находится только в области видимости) в теле оператора if.

В качестве альтернативы вы можете использовать оператор guard, который позволяет вам выйти из функции, если переменная равна nil:

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

В Swift 2 были добавлены операторы Guard. Guard позволяет вам сохранять "золотой путь" в вашем коде и избегать постоянно увеличивающихся уровней вложенных if, которые иногда возникают в результате использования необязательного связывания "if let".

Существует также конструкция, называемая "оператор слияния ноль". Он принимает форму "необязательный_вар", "замена_вал". Он возвращает необязательную переменную того же типа, что и данные, содержащиеся в необязательной переменной. Если необязательный параметр содержит nil, он возвращает значение выражения после "??" условное обозначение.

Таким образом, вы можете использовать такой код:

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

Вы также можете использовать try/catch или обработку ошибок guard, но, как правило, один из других методов выше - более чистый.

РЕДАКТИРОВАТЬ:

Другой, несколько более тонкий хитрость с опциями - это "неявно развернутые опционы". Когда мы объявляем foo, мы можем сказать:

var foo: String!

В этом случае foo все еще не обязателен, но вам не нужно разворачивать его, чтобы ссылаться на него. Это означает, что каждый раз, когда вы пытаетесь сослаться на foo, вы теряете значение, если оно равно нулю.

Итак, этот код:

var foo: String!


let upperFoo = foo.capitalizedString

Сбой при ссылке на свойство foo capitalizedString, даже если мы не распаковываем foo. отпечаток выглядит хорошо, но это не так.

Таким образом, вы хотите быть очень осторожным с неявно развернутыми опциями. (и, возможно, даже избегайте их полностью, пока у вас не будет четкого понимания дополнительных возможностей.)

Итог: когда вы впервые изучаете Swift, сделайте вид "!" характер не является частью языка. Это может привести к неприятностям.

Во-первых, вы должны знать, что такое необязательное значение. Вы можете перейти к программе быстрого запуска

для деталей.

Во-вторых, вы должны знать, что необязательное значение имеет два состояния. Один - полное значение, а другой - нулевое значение. Поэтому, прежде чем реализовать необязательное значение, вы должны проверить, в каком оно состоянии.

Ты можешь использовать if let ... или же guard let ... else и так далее.

Еще один способ, если вы не хотите проверять его состояние перед вашей машиной, вы также можете использовать var buildingName = buildingName ?? "buildingName" вместо.

Поскольку приведенные выше ответы четко объясняют, как безопасно играть с Optionals. Я постараюсь объяснить, что на самом деле опционально быстро.

Другой способ объявить необязательную переменную

var i : Optional<Int>

А необязательный тип - это не что иное, как перечисление с двумя падежами, т.е.

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

Таким образом, чтобы присвоить ноль нашей переменной "я". Мы можем var i = Optional<Int>.noneили чтобы присвоить значение, мы передадим некоторое значение var i = Optional<Int>.some(28)

Согласно Свифту, "ноль" - это отсутствие стоимости. И создать экземпляр, инициализированный с nil Мы должны соответствовать протоколу под названием ExpressibleByNilLiteral и здорово, если вы догадались, только Optionals соответствовать ExpressibleByNilLiteral и соответствие другим типам не рекомендуется.

ExpressibleByNilLiteral имеет единственный метод с именем init(nilLiteral:) который инициализирует instace с нулем. Вы обычно не вызываете этот метод, и согласно быстрой документации не рекомендуется вызывать этот инициализатор напрямую, так как компилятор вызывает его всякий раз, когда вы инициализируете необязательный тип с помощью nil буквальный.

Даже я должен обернуть (не каламбур) мою голову вокруг Факультативного: DHappy Swfting All.

По сути, вы пытались использовать значение nil в тех местах, где Swift допускает только не nil, "обманывая" компилятор, думая, что там есть значение nil, что позволяет вашему приложению компилироваться.

Есть несколько сценариев, которые приводят к такой фатальной ошибке:

  1. принудительное развертывание:

    let user = someVariable!
    

    Если someVariable ноль, тогда вы получите крах. Делая принудительную развёртку, вы перекладывали ответственность компилятора на вас, в основном выполняя принудительную развёртку, вы гарантируете компилятору, что там никогда не будет значений nil. И угадайте, что произойдет, если это произойдет?

    Решение? Используйте необязательную привязку (иначе 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 = "none yet"
        }
    
        func nicerName() {
            return "Mr/Ms " + name
        }
    }
    

    Теперь, если никто не напутает с name свойство, установив его в nilто работает как положено, однако если User инициализируется из JSON, в котором отсутствует name ключ, то вы получите фатальную ошибку при попытке использовать свойство.

    Решение? Не используйте их:) Если вы не уверены на 102%, что свойство всегда будет иметь значение, отличное от нуля, к моменту его использования. Однако в большинстве случаев преобразование его в необязательный или необязательный будет работать. Если вы сделаете его необязательным, компилятор также поможет вам, указав пропущенные вами пути кода, указав значение этого свойства.

  4. Несвязанные розетки. Это частный случай сценария № 3. По сути, у вас есть некоторый загруженный XIB класс, который вы хотите использовать.

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

    Теперь, если вы пропустили подключение к розетке из редактора XIB, приложение вылетит, как только вы захотите использовать розетку. Решение? Убедитесь, что все розетки подключены. Или используйте ? оператор на них: emailTextField?.text = "my@email.com", Или объявите выход как необязательный, хотя в этом случае компилятор заставит вас развернуть его по всему коду.

  5. Значения, поступающие из Objective-C, и которые не имеют аннотаций обнуляемости. Давайте предположим, что у нас есть следующий класс Objective-C:

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

    Теперь, если аннотации обнуляемости не указаны (явно или через NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_END), то name недвижимость будет импортирована в Swift as String! (IUO - неявно развернутый необязательный). Как только какой-то swift-код захочет использовать это значение, в ноль случаев произойдет сбой.

    Решение? Добавьте аннулируемые аннотации к вашему коду Objective-C. Однако, будьте осторожны, компилятор Objective-C немного допустим, когда дело доходит до обнуляемости, вы можете получить нулевые значения, даже если вы явно пометили их как nonnull,

Однажды у меня была эта ошибка, когда я пытался установить свои значения Outlets из метода подготовки к переходу следующим образом:

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
}

Я надеюсь, что этот ответ поможет всем, кто столкнулся с той же проблемой, поскольку я обнаружил, что отмеченный ответ является отличным ресурсом для понимания дополнительных возможностей и того, как они работают, но сам не решил эту проблему напрямую.

Если вы получаете эту ошибку в CollectionView, попробуйте также создать файл CustomCell и Custom xib.

добавьте этот код в ViewDidLoad() на mainVC.

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

Ошибки EXC_BAD_INSTRUCTION а также fatal error: unexpectedly found nil while unwrapping an Optional value появляется больше всего, когда вы объявили @IBOutlet, но не подключен к раскадровке.

Вы также должны узнать о том, как работают дополнительные устройства, упомянутые в других ответах, но это единственный случай, который мне больше всего кажется.

Это более важный комментарий, и поэтому неявно развернутые опции могут быть обманчивы, когда дело доходит до отладки. nil ценности.

Подумайте о следующем коде: он компилируется без ошибок / предупреждений:

c1.address.city = c3.address.city

Тем не менее, во время выполнения он выдает следующую ошибку: Неустранимая ошибка: неожиданно обнаружен ноль при развертывании необязательного значения

Можете ли вы сказать мне, какой объект 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
}

Короче говоря, используя 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
}

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)

Надеюсь, это сработает :-)

простыми словами, вы пытаетесь использовать значение необязательной переменной, равное нулю. быстрое исправление может быть использовано guard или if let вместо принудительного развертывания, как положить ! в конце переменной

Свифт 5.7 +

if letсокращение для затенения существующей необязательной переменной

Приведенные выше ответы ясно объясняют, почему возникает эта проблема и как ее решить. Но есть решения этой проблемы от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

У меня это случалось несколько раз без видимой причины в Xcode 15. Проверка другой ветки (например, основной), а затем повторная проверка вашего рабочего места, кажется, исправляет это. Не знаю, почему...

Я столкнулся с этой ошибкой при переходе от контроллера табличного представления к контроллеру представления, потому что я забыл указать имя настраиваемого класса для контроллера представления в основной раскадровке.

Что-то простое, что стоит проверить, все ли в порядке

В моем случае я установил переменную в 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)
    }
    

}

В контексте Realm, если он терпит неудачу вNSClassFromString(realmClass)тогда ваш вновь созданный класс/структура Realmable не будет зарегистрирован.

вызовRealm.registerRealmables(MyClass.self, MyOtherClass.self,...)в начале жизненного цикла приложения (appDidFinishLaunching)

Это связано с тем, что вы пытаетесь использовать значение, которое может быть нулевым, но вы решили, что не хотите его проверять, а вместо этого предполагаете его набор при его использовании и определяете его как !, существуют разные философии по этому поводу. использование набора переменных в качестве принудительной развертки, некоторые люди вообще против их использования, я лично думаю, что они подходят для вещей, которые будут постоянно падать и о которых легко рассуждать, обычно это ссылки на ресурсы, такие как выходы в xib-файлы или использование изображений с вашим приложением, которые являются частью ваших активов, если они не настроены должным образом, ваше приложение сразу же выйдет из строя по очень очевидной причине, вы можете столкнуться с трудностями, когда порядок создаваемых объектов может быть неопределенны, и попытки найти решения для этого могут быть трудными, это обычно означает плохой дизайн, поскольку даже если вы делаете их необязательными,вызовы вашей дополнительной переменной могут никогда не выполняться, некоторые проекты могут потребовать использования принудительной развертки по соображениям безопасности, такие как банковские приложения, потому что они хотят, чтобы приложение вышло из строя, а не продолжало работать незапланированным образом.

Пока другие ответы...

Все, что вам нужно, это знать, что существуют объекты, допускающие значение NULL. И они не могут иметь никакого значения («ноль»). Ошибка означает, что вы пытаетесь получить значение переменной в тот момент, когда имеется ноль, а не значение.

Наверняка вы получили эту ошибку в строке кода с "!" это означает: «Я гарантирую, что это значение, допускающее значение NULL, не равно нулю, просто используйте его».

Способы избежать проблемы:

  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

И ПОМНИТЕ: Использование "!" это действительно плохая практика.

Swift 5 и выше (опционально и опционально)

class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if let buildingNumber = buildingNumber, let street = street {
            return "\(buildingNumber) \(street)"
        } else if buildingName != nil {
            return buildingName
        } else {
            return nil
        }
    }
}

фатальная ошибка: неожиданно найден ноль при развертывании необязательного значения

Это говорит о том, что вы используете переменную, значение которой не инициализировано или установлено в ноль.

Например

var tempVar: String?
print(tempVar!)

tempVar не инициализируется, поэтому в этом случае происходит сбой приложения, поэтому вы должны использовать

print(tempVar ?? "") 

Пожалуйста, обратитесь к Дополнительной цепочке для более подробной информации

Другие вопросы по тегам