Можно ли разрешить 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 } } 
  • Несколько NSURLSession для загрузки Json
  • Создание круга прогресса в качестве приложения WKInterfaceImage в Watch
  • Ошибка Swift 2.0 Downcast из '?' to '' только разворачивает необязательный
  • TouchID с KeyChain - Ввод пароля отображается неправильно (Swift)
  • Swift: возврат к просмотру таблицы после выбора результата поиска
  • Swift3 Xcode 8: «none» недоступен: используйте для создания пустого набора опций; Что мне делать?
  • Свойство IBOutlet возвращает сообщение «Can not unwлять Optional.None»
  • Изменение цвета индикатора активности на черный
  • Ошибка XCode 6 Beta 4 - «При запуске была обнаружена ошибка (Domain = com.apple.CoreSimulator.SimError, Code = 146)»
  • Руководство по основным данным с Swift 3
  • Полученная ошибка: Error Domain = com.facebook.sdk.core Код = 8 "(null)"
  • Interesting Posts

    Беспокойный издевательский синглтон для модульного тестирования в Swift

    KeyboardShrinksView позволяет потерять фокус

    Новое для Swift и confused – Храните большую константу / набор данных в классе Swift

    Определите устройство (iPhone, iPod Touch) с iPhone SDK

    Как поймать сбой Swift и сделать некоторые каротажи

    applicationDidBecomeActive запускается после загрузки ViewController

    обработка зависимостей для проекта iOS Framework

    Как правильно открыть и закрыть NSStream в другом потоке

    Шаблоны проектов расширения не отображаются в Xcode 6

    Использование UDID в приложениях pre-iOS6 (и IDFA для 6.0+)

    Как определить тип очереди отправки (последовательный или параллельный)?

    Преобразование диапазона <Int> в диапазон <String.Index>

    Как добавить пользовательский UIView в панель навигации в iOS7 +, как это сделать

    Найти все рабочие IP-адреса в сети Wi-Fi маршрутизатора ios

    Приложение разбилось при импорте песен из библиотеки Ipod в Iphone для iOs 5.0

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.