Вопрос
Документы Apple указывают, что:
Наблюдатели willSet и didSet не вызываются при первой инициализации свойства. Они вызываются, только когда значение свойства установлено вне контекста инициализации.
Можно ли заставить их вызываться во время инициализации?
Зачем?
Допустим, у меня есть этот класс
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
Я создал метод doStuff
, чтобы сделать обработку вызовов более лаконичной, но я бы предпочел просто обработать свойство внутри didSet
функции. Есть ли способ заставить это вызвать во время инициализации?
Обновить
Я решил просто удалить удобство Intializer для моего класса и заставить вас установить свойство после инициализации. Это позволяет мне знать, didSet
что всегда будет называться. Я не решил, будет ли это лучше в целом, но это хорошо подходит для моей ситуации.
defer
:convenience init(someProperty: AnyObject) { self.init() defer { self.someProperty = someProperty }
Ответы:
Создайте собственный метод set и используйте его в своем методе init:
источник
someProperty
как тип:AnyObject!
(неявно развернутый необязательный), вы позволяетеself
полностью инициализировать безsomeProperty
установки. Когда вы звоните,setSomeProperty(someProperty)
вы звоните эквивалентself.setSomeProperty(someProperty)
. Обычно вы не сможете сделать это, потомуself
что не были полностью инициализированы. ТакsomeProperty
как не требует инициализации и вы вызываете метод, зависящий отself
, Swift покидает контекст инициализации иdidSet
запускается.init() { *HERE* }
будет вызывать didSet. Отлично подходит для этого вопроса, но использование вторичной функции для установки некоторых значений приводит к вызову didSet. Не очень хорошо, если вы хотите повторно использовать эту функцию установки.Если вы используете
defer
внутри инициализатора , для обновления любых необязательных свойств или дальнейшего обновления не необязательных свойств, которые вы уже инициализировали, и после того, как вы вызвали какие-либоsuper.init()
методы, будут вызваны вашиwillSet
,didSet
и т. Д. Я считаю, что это удобнее, чем реализовывать отдельные методы, которые вы должны отслеживать, звоня в нужных местах.Например:
Даст:
источник
defer
. Спасибо.Как вариант ответа Оливера, вы можете заключить строки в замыкание. Например:
Изменить: Брайан Вестфал ответ лучше imho. Приятно, что он намекает на намерения.
источник
У меня была такая же проблема, и это работает для меня
источник
Это работает, если вы делаете это в подклассе
В
a
примереdidSet
не срабатывает. Но вb
примереdidSet
это срабатывает, потому что это в подклассе. Он должен сделать что - то с тем, что наinitialization context
самом деле означает, в данном случаеsuperclass
сделал заботу о том , чтоисточник
Хотя это не решение проблемы, альтернативный способ сделать это - использовать конструктор класса:
источник
someProperty
поскольку оно не будет давать ему значение во время инициализации.В частном случае , когда вы хотите , чтобы вызвать
willSet
илиdidSet
внутриinit
имущества , имеющихся в вашем суперкласса, вы можете просто присвоить супер свойство непосредственно:Обратите внимание, что в этом случае тоже будет работать решение Шарлизма с замыканием. Так что мое решение - просто альтернатива.
источник
Вы можете решить это в obj-с способом:
источник
self.someProperty
вы выходите из области инициализации. Я верю, что то же самое может быть достигнуто, делаяvar someProperty: AnyObject! = nil { didSet { ... } }
. Тем не менее, некоторые могут оценить это как