С помощью следующего кода я пытаюсь определить простой класс модели и его сбойный инициализатор, который принимает словарь (json-) в качестве параметра. Инициализатор должен вернуться, nil
если имя пользователя не определено в исходном json.
1. Почему код не компилируется? В сообщении об ошибке говорится:
Все сохраненные свойства экземпляра класса должны быть инициализированы перед возвратом nil из инициализатора.
В этом нет смысла. Зачем мне инициализировать эти свойства, когда я планирую вернуться nil
?
2. Правильный ли мой подход или есть другие идеи или общие шаблоны для достижения моей цели?
class User: NSObject {
let userName: String
let isSuperUser: Bool = false
let someDetails: [String]?
init?(dictionary: NSDictionary) {
if let value: String = dictionary["user_name"] as? String {
userName = value
}
else {
return nil
}
if let value: Bool = dictionary["super_user"] as? Bool {
isSuperUser = value
}
someDetails = dictionary["some_details"] as? Array
super.init()
}
}
swift
object-initializers
Кай Хуппманн
источник
источник
canSetCalculableProperties
логический параметр, позволяющий моему инициализатору вычислять свойства, которые могут или не могут быть созданы на лету. Например, еслиdateCreated
ключ отсутствует, и я могу установить свойство на лету, потому чтоcanSetCalculableProperties
параметр имеет значение true, я просто устанавливаю его на текущую дату.Ответы:
Обновление: из журнала изменений Swift 2.2 (выпущено 21 марта 2016 г.):
Для Swift 2.1 и ранее:
Согласно документации Apple (и ошибке вашего компилятора), класс должен инициализировать все свои сохраненные свойства перед возвратом
nil
из неудачного инициализатора:Примечание. На самом деле он отлично работает для структур и перечислений, но не для классов.
Предлагаемый способ обработки сохраненных свойств, которые не могут быть инициализированы до сбоя инициализатора, - объявить их как неявно развернутые необязательные параметры.
Пример из документов:
В вашем случае, однако, простое определение
userName
как aString!
не устраняет ошибку компиляции, потому что вам все еще нужно беспокоиться об инициализации свойств в вашем базовом классеNSObject
. К счастью, сuserName
определением как aString!
, вы можете вызватьsuper.init()
перед собой,return nil
который запустит вашNSObject
базовый класс и исправит ошибку компиляции.источник
Product
класс) не может вызвать сбой инициализации перед присвоением определенного значения, даже если в документации это указано. Документы не синхронизированы с последней версией Swift.var
Вместо этого рекомендуется сделать это на данный моментlet
. Источник: Крис Латтнер .По словам Криса Латтнера, это ошибка. Вот что он говорит:
Источник
РЕДАКТИРОВАТЬ:
Итак, swift теперь имеет открытый исходный код и, согласно этому списку изменений, теперь исправлен в снимках swift 2.2.
источник
Я согласен с тем, что ответ Майка С - это рекомендация Apple, но я не думаю, что это лучшая практика. Весь смысл сильной системы типов состоит в том, чтобы переместить ошибки времени выполнения во время компиляции. Это «решение» противоречит этой цели. ИМХО, лучше было бы инициализировать имя пользователя на
""
а затем проверить его после super.init (). Если пустые имена пользователей разрешены, установите флаг.источник
Другой способ обойти это ограничение - работать с классом-функциями для инициализации. Возможно, вы даже захотите переместить эту функцию в расширение:
Использование его станет:
источник
Хотя был выпущен Swift 2.2, и вам больше не нужно полностью инициализировать объект перед ошибкой инициализатора, вам нужно подождать, пока https://bugs.swift.org/browse/SR-704 не будет исправлен.
источник
Я узнал, что это можно сделать в Swift 1.2.
Есть некоторые условия:
Пример:
источник
Выдержка из: Apple Inc. « Быстрый язык программирования. IBooks. https://itun.es/sg/jEUH0.l
источник
Вы можете использовать удобный init :
источник