Какие варианты объявления опциональных свойств в Swift и их отличие?
Что проверяют
Понимаете ли вы, что опционал в Swift это обычное перечисление, а не особый «nullable-тип», и чем ! в объявлении отличается от ?. Следом обычно просят показать безопасное разворачивание и спрашивают, где String! оправдан.
Как отвечать
Основные варианты:
var name: String?: сахар дляOptional<String>. Уvarзначение по умолчаниюnil, вinitзадавать не обязательно;var name: Optional<String>: тот же тип явно. Встречается в дженериках иextension Optional where Wrapped == String; неявногоnilу такой записи нет;var name: String!: неявно развёрнутый опционал (IUO). Со Swift 4.2 это не отдельный тип, аOptionalс разрешением развернуть принудительно. Где контекст допускает опционал, он им и остаётся:let copy = nameполучитString?. Если внутриnil, обращение крашит приложение;let name: String?: неявногоnilнет, значение присваивают в инициализаторе;weak var delegate: Delegate?: слабая ссылка обязана быть опциональнымvar, ARC обнулит её при освобождении объекта;@objc optional varв@objc protocol: необязательное требование протокола. Реализация может свойство не объявлять, а чтение через протокол вернёт опционал.
Внутри Optional это enum с кейсами .none и .some(Wrapped), поэтому по нему работает switch. Разворачивают через if let, guard let, короткую форму if let name со Swift 5.7, ?? и цепочку user?.address?.city.
Где спотыкаются
Ставят ! везде, где лень думать об инициализации. Оправданные случаи узкие: @IBOutlet и свойства, которые гарантированно заполняются до первого обращения.
Считают String! отдельным типом и удивляются, что после присваивания в новую переменную значение стало опционалом.
Путают опциональное свойство и опциональное требование протокола. Без @objc необязательных требований нет, в чистом Swift их заменяет реализация по умолчанию в extension.