Получение ошибки & ldquo; Тема 1: Неустранимая ошибка: Неожиданно найдено нуль при развертывании необязательного значения & rdquo; [dубликат]

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

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

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

294
задан 8 revs, 5 users 58% 19 May 2018 в 14:26
поделиться

6 ответов

Неустранимая ошибка: неожиданно найден nil при разворачивании необязательного значения

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

Например

var tempVar: String?
print(tempVar!)

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

print(tempVar ?? "") 

Для получения более подробной информации см. раздел «Дополнительная цепочка»

-3
ответ дан 2 revs, 2 users 83% 15 August 2018 в 12:24
поделиться

TL; DR answer

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

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

Объявить переменную опционально (?), а не неявно развернутые опции (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)")

Этот ответ должен был быть сжатым, очень мало исключений

43
ответ дан 6 revs, 3 users 91% 15 August 2018 в 12:24
поделиться

Этот вопрос возникает ВСЕ ВРЕМЯ на SO. Это одна из первых вещей, с которой сталкиваются новые разработчики Swift.

Фон:

Swift использует концепцию «Опционы» для обработки значений, которые могут содержать значение, или нет. В других языках, таких как C, вы можете сохранить значение 0 в переменной, чтобы указать, что оно не содержит значения. Однако, что, если 0 является допустимым значением? Тогда вы можете использовать -1. Что, если -1 является допустимым значением? И так далее.

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

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

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

Необязательно необходимо «распаковать», чтобы получить значение внутри.

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

Если вы действительно ВСЕ ВРЕМЯ не знаете, что вы делаете, избегайте «!». оператор разворачивания силы. Вероятно, это самый большой источник сбоев для начинающих программистов Swift.

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

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

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

Ниже приведен пример необязательной привязки с нашим foo необязательным:

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

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

В качестве альтернативы вы можете использовать инструкцию охраны, которая позволяет вам выйти из вашей функции если переменная равна 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. Guard позволяет вам сохранить «золотой путь» через ваш код и избегать постоянно растущих уровней вложенных ifs, которые иногда возникают из используя необязательную привязку «if let».

Существует также конструкция, называемая «nol-коалесцирующим оператором». Он принимает форму «optional_var ?? replacement_val». Он возвращает необязательную переменную с тем же типом, что и данные, содержащиеся в необязательном. Если опция содержит nil, она возвращает значение выражения после "??" символ.

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

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

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

EDIT:

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

var foo: String!

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

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

var foo: String!


let upperFoo = foo.capitalizedString

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

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

Нижняя строка. Когда вы впервые изучаете Swift, притворитесь, что символ «!» не является частью язык. Вероятно, вы получите меня nto проблема.

34
ответ дан Duncan C 15 August 2018 в 12:24
поделиться
  • 1
    Вы должны подумать о том, чтобы сделать это общедоступной вики. – vacawama 28 February 2016 в 15:42
  • 2
    Отредактируйте свой ответ, а под полем редактирования справа появится флажок сообщества wiki . Вы больше не будете отвечать за ответ, но я знаю, что это не вопиющая репутация. – vacawama 28 February 2016 в 15:49
  • 3
    [D0] meta.stackexchange.com/q/11740/200104 – vacawama 28 February 2016 в 15:55
  • 4
    Учитывая, что этот вопрос задан в миллион раз на сайте, если я собираюсь потратить время, чтобы опубликовать вопрос с автоответчиком в качестве канонического ответа на вопрос, я надеюсь, что ответ будет намного более полным, чем это. В предложениях guard ничего нет. Нет ничего о том, как использовать if var, который так же корректен, как и if let. Нет ничего о where предложениях, которые, как мне кажется, стоит упомянуть, когда мы говорим о привязке if let (во многих случаях он удаляет целый слой вложенности). Нет ничего о дополнительной цепочке. – nhgrif 28 February 2016 в 23:00
  • 5
    И когда вы указываете неявно развернутые опции, вы даже не упоминаете, что вы можете использовать все вышеупомянутые необязательные трюки, чтобы безопасно разворачивать неявно развернутые опции. Мы также не рассматриваем разворачивание нескольких опций в том же предложении. – nhgrif 28 February 2016 в 23:01

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

для деталей.

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

Вы можете использовать if let ... или guard let ... else и т. Д.

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

8
ответ дан QiunCheng 15 August 2018 в 12:24
поделиться

Так как в приведенных выше ответах четко объясняется, как безопасно играть с опциями.

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

var i : Optional<Int>

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

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

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

. Согласно swift, «nil» - это отсутствие значения. И создать экземпляр, инициализированный с помощью nil. Мы должны соответствовать протоколу с именем ExpressibleByNilLiteral и большим, если вы его догадались, только Optionals соответствуют ExpressibleByNilLiteral и соответствуют другим типам.

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

Даже мне приходится обертывать (нет каламбур) моя голова вокруг опций: D Happy Swfting All.

8
ответ дан Tharzeez 15 August 2018 в 12:24
поделиться

У меня была эта ошибка, когда я пытался установить значения Outlets из метода подготовки к методу 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)
        }
    }
}

Destination Controller:

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

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

3
ответ дан Wissa 15 August 2018 в 12:24
поделиться

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

Похожие вопросы: