Можно ли разрешить didSet для вызова во время инициализации в Swift?

Вопрос

Документы 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 . Есть ли способ заставить это вызвать во время инициализации?

Обновить

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

8 Solutions collect form web for “Можно ли разрешить didSet для вызова во время инициализации в Swift?”

Создайте собственный метод set и используйте его в вашем init-Method:

 class SomeClass { var someProperty: AnyObject! { didSet { //do some Stuff } } init(someProperty: AnyObject) { setSomeProperty(someProperty) } func setSomeProperty(newValue:AnyObject) { self.someProperty = newValue } } 

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

Например:

 public class MyNewType : NSObject { public var myRequiredField:Int public var myOptionalField:Float? { willSet { if let newValue = newValue { print("I'm going to change to \(newValue)") } } didSet { if let myOptionalField = self.myOptionalField { print("Now I'm \(myOptionalField)") } } } override public init() { self.myRequiredField = 1 super.init() // Non-defered self.myOptionalField = 6.28 // Defered defer { self.myOptionalField = 3.14 } } } 

будет давать:

 I'm going to change to 3.14 Now I'm 3.14 

Как вариант ответа Оливера, вы можете обернуть линии в закрытии. Например:

 class Classy { var foo: Int! { didSet { doStuff() } } init( foo: Int ) { // closure invokes didSet ({ self.foo = foo })() } } 

Редактировать: ответ Брайана Вестфала более приятный. Самое приятное в том, что он намекает на намерение.

У меня была такая же проблема, и это работает для меня

 class SomeClass { var someProperty: AnyObject { didSet { doStuff() } } init(someProperty: AnyObject) { defer { self.someProperty = someProperty } } func doStuff() { // do stuff now that someProperty is set } } 

Это работает, если вы делаете это в подклассе

 class Base { var someProperty: AnyObject { didSet { doStuff() } } required init() { someProperty = "hello" } func doStuff() { print(someProperty) } } class SomeClass: Base { required init() { super.init() someProperty = "hello" } } let a = Base() let b = SomeClass() 

В примере didSet не запускается. Но, к примеру, didSet запускается, так как он находится в подклассе. Он должен что-то сделать с тем, что действительно означает initialization context , в этом случае superclass действительно заботился об этом

Хотя это не решение, альтернативный способ обойти это будет использовать конструктор класса:

 class SomeClass { var someProperty: AnyObject { didSet { // do stuff } } class func createInstance(someProperty: AnyObject) -> SomeClass { let instance = SomeClass() instance.someProperty = someProperty return instance } } 

В конкретном случае, когда вы хотите вызывать willSet или didSet внутри init для свойства, доступного в вашем суперклассе, вы можете просто назначить свой супер-объект напрямую:

 override init(frame: CGRect) { super.init(frame: frame) // this will call `willSet` and `didSet` someProperty = super.someProperty } 

Обратите внимание, что решение карлизма с закрытием всегда будет работать и в этом случае. Поэтому мое решение – это просто альтернатива.

Вы можете решить это с помощью obj-с:

 class SomeClass { private var _someProperty: AnyObject! var someProperty: AnyObject{ get{ return _someProperty } set{ _someProperty = newValue doStuff() } } init(someProperty: AnyObject) { self.someProperty = someProperty doStuff() } func doStuff() { // do stuff now that someProperty is set } } 
  • Запуск одной функции за другой завершается
  • Пользовательская ячейка в UITableView сдвигается сразу после салфетки для редактирования
  • Тест iOS / Swift для UIAlertController / UIAlertView
  • Как интегрировать Linkedin SDK в приложение для входа и совместного использования с помощью Swift
  • IOS загружает изображения из URL с помощью SDWebImage
  • Скачать dSYM не удается «Отсутствует версия приложения»
  • Как проверить, произошло ли нажатие на место в определенном месте
  • Использование NSFileManager и createDirectoryAtPath в Swift
  • Есть ли способ, чтобы текст в ярлыке автоматически обновлял дисплей
  • Swift Framework с libxml
  • Как изменить изображение UIButton в Swift
  • Как справиться с инициализатором по умолчанию, когда переменная не инициализирована Использование Struct
  • PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.