Ответ 1
У меня просто была та же проблема.
Как сказал GoZoner, пометка ваших переменных как необязательная будет работать. Это не очень элегантный способ, потому что вам нужно разворачивать значение каждый раз, когда вы хотите получить к нему доступ.
Я напишу запрос об улучшении с Apple, возможно, мы могли бы получить что-то вроде метода "beforeInit", который вызывается перед каждым init, где мы можем назначить переменные, поэтому нам не нужно использовать необязательные vars.
До тех пор я просто поставлю все назначения в метод commonInit, который вызывается из выделенных инициализаторов. Например:.
class GradientView: UIView {
var gradientLayer: CAGradientLayer? // marked as optional, so it does not have to be assigned before super.init
func commonInit() {
gradientLayer = CAGradientLayer()
gradientLayer!.frame = self.bounds
// more setup
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
commonInit()
}
init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer!.frame = self.bounds // unwrap explicitly because the var is marked optional
}
}
Благодаря Дэвиду я снова взглянул на книгу, и я нашел кое-что, что может быть полезно для наших усилий по дедупликации, не используя необязательный переменный хак. Для инициализации переменной можно использовать замыкание.
Установка значения свойства по умолчанию с закрытием или функцией
Если для значения по умолчанию для хранимых свойств требуется некоторая настройка или настройка, вы можете использовать функцию закрытия или глобальную функцию для предоставления настраиваемого значения по умолчанию для этого свойства. Всякий раз, когда инициализируется новый экземпляр типа, к которому принадлежит свойство, замыкается или функция, и его возвращаемое значение присваивается как значение по умолчанию свойства. Эти типы замыканий или функций обычно создают временное значение того же типа, что и свойство, портят это значение для представления желаемого начального состояния, а затем возвращают это временное значение, которое будет использоваться как значение по умолчанию свойства.
Вот схема скелета о том, как можно использовать закрытие для предоставления значения свойства по умолчанию:
class SomeClass { let someProperty: SomeType = { // create a default value for someProperty inside this closure // someValue must be of the same type as SomeType return someValue }() }
Обратите внимание, что за закрытием заканчивается фигурная скобка, за которой следует пустая пара скобок. Это означает, что Swift немедленно выполнит закрытие. Если вы опустите эти круглые скобки, вы пытаетесь присвоить это свойство закрытию, а не возвращаемое значение закрытия.
Примечание
Если вы используете закрытие для инициализации свойства, помните, что остальная часть экземпляра еще не была инициализирована в точке, в которой выполняется закрытие. Это означает, что вы не можете получить доступ к каким-либо другим значениям свойств из вашего закрытия, даже если эти свойства имеют значения по умолчанию. Вы также не можете использовать неявное свойство self или вызвать любой из методов экземпляров.
Отрывок из: Apple Inc. "Быстрый язык программирования". интерактивные книги. https://itun.es/de/jEUH0.l
Это то, как я буду использовать с этого момента, потому что он не обходит полезную функцию, не допускающую nil на переменные. Для моего примера это будет выглядеть так:
class GradientView: UIView {
var gradientLayer: CAGradientLayer = {
return CAGradientLayer()
}()
func commonInit() {
gradientLayer.frame = self.bounds
/* more setup */
}
init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
commonInit()
}
init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
}