На сегодняшний день у нас есть 6 практически одинаковых вопросов по сабжу. Давайте один раз напишем полный ответ по этому вопросу и будем в будущем на него ссылаться. Пока публикую под своим именем, если будут добавления/редактирования переставим на сообщество.
Ответ
Давайте один последний раз пройдемся по unexpectedly found nil while unwrapping an Optional value и больше никогда к нему не будем возвращаться.
Когда вы создаете переменные инстанса, swift от вас хочет, чтобы вы либо сразу им присвоили значения по дефолту, либо инициализировали их в init. Во многих случаях это нам не подходит, тогда мы объявляем свои переменные как optional.
var test:Int? // вопрос в конце, это объявление опциональной переменной
Что значит Optional? Это значит, что вместо просто переменной, например Int, мы получаем инумерацию из двух значений: none и some(Wrapped). Вот это Wrapped и есть значение нашей переменной.
Соответственно, если переменная не присвоена, то при попытке к ней обратиться, получим none т.е. nil.
Если же она содержит значение мы получим Optional(value)
Вот пример:
var test:Int?
print(test) // напечатает 'nil'
test = 42
print(test) // напечатает 'Optional(42)'
Далее, чтобы избавиться от этого Optional нам надо ее развернуть (unwrap), то есть сказать, что мы точно уверены, что там что то есть и мы хотим получить это самое что то. Другими словами, вместо Optional(value), получить value. Чтобы сделать принудительное разворачивание (forced unwrap) мы добавляем '!'. При этом, если переменная не присвоена, мы получим крэш - тот самый unexpectedly found nil while unwrapping an Optional value.
Пример:
var test:Int?
print(test!) // крэш unexpectedly found nil и т.д.
var test2:Int?
test2 = 42
print(test2!) // напечатает 42
Дальше, если мы хотим создать переменную как Optional, но точно знаем, что в нее будет что-то присвоено до того, как мы ее будем читать первый раз, мы можем ее объявить как Implicitly Unwrapped Optional Type, посредством добавления '!' в объявлении. В этом случае, она опять же будет Optional, но система будет ее принудительно разворачивать (force unwrap) при любом обращении к ней.
var test:Int! // '!' в конце, это обявление implicitly unwrapped optional
print(test) // крэш unexpectedly found nil...
var test2:Int!
test2 = 42
print(test2) // напечатает 42
А что делать, если мы понятия не имеем есть там что то в этой optional или нет?
var test:Int?
if(test != nil) {
print(test!) // развернутое значение
} else {
print(test) // nil
}
Либо другой способ, который создает временную переменную с развернутым значением
var test:Int?
if let unwrappedTest = test {
print(unwrappedTest)
} else {
print("no value")
}
Ну и если вам надо force unwrapped превратить обратно в Optional:
var test:Int!
print(test as Optional) // напечатает nil
Optional chaining:
Есть еще такая ситуация, когда надо сделать цепочку вызовов, при этом где то в цепочке может содержаться опциональная перменная.
Вот такой пример дает apple:
Допустим есть класс Residence, и в нем есть переменная numberOfRooms; и есть класс Person, который имеет опциональную переменную типа Residence. Другими словами у человека может быть жилье, с каким то количеством комнат, а может и не быть жилья. То есть при попытке обратиться к человек-жилье-комнаты, мы можем наткнуться на nil вместо жилья.
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
Теперь мы хотим создать новый Person, и узнать сколько комнат в его жилище (при этом residence может быть nil поскольку он Optional). Для этого мы говорим системе, что мы хотим делать с опциональным значением - либо оставлять его опциональным ('?') со всеми вытекающими последствиями, в частности получить nil вместо количества комнат; либо принудительно его разворачивать, при этом имея риск получить fatal error.
let john = Person()
print(john.residence!.numberOfRooms) // крэш unexpectedly ...
print(john.residence?.numberOfRooms) // напечатает nil
let tom = Person()
tom.residence = Residence()
print(tom.residence!.numberOfRooms) // напечатает 1
print(tom.residence?.numberOfRooms) // напечатает Optional(1)
Тут надо заметить, что хотя numberOfRooms не является опциональной, она в этой цепи становится таковой, поскольку цепь идет через опциональную residence?
Комментариев нет:
Отправить комментарий