ios - did - lazy var swift
¿Es posible permitir que se llame a didSet durante la inicialización en Swift? (8)
Como una variación de la respuesta de Oliver, podrías envolver las líneas en un cierre. P.ej:
class Classy {
var foo: Int! { didSet { doStuff() } }
init( foo: Int ) {
// closure invokes didSet
({ self.foo = foo })()
}
}
Editar: La respuesta de Brian Westphal es más agradable. Lo bueno de él es que insinúa la intención.
Pregunta
Los documentos de Apple especifican que:
Los observadores willSet y didSet no se invocan cuando una propiedad se inicializa por primera vez. Solo se llaman cuando el valor de la propiedad se establece fuera de un contexto de inicialización.
¿Es posible forzar que se llamen durante la inicialización?
¿Por qué?
Digamos que tengo esta clase
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
self.someProperty = someProperty
doStuff()
}
func doStuff() {
// do stuff now that someProperty is set
}
}
doStuff
el método doStuff
, para hacer las llamadas de procesamiento más concisas, pero preferiría simplemente procesar la propiedad dentro de la función didSet
. ¿Hay alguna manera de forzar esto a llamar durante la inicialización?
Actualizar
Decidí simplemente eliminar el intializador de conveniencia para mi clase y forzarlo a establecer la propiedad después de la inicialización. Esto me permite saber que siempre se llamará a didSet
. No he decidido si esto es mejor en general, pero se adapta bien a mi situación.
Cree un propio set-Method y úselo dentro de su método init:
class SomeClass {
var someProperty: AnyObject! {
didSet {
//do some Stuff
}
}
init(someProperty: AnyObject) {
setSomeProperty(someProperty)
}
func setSomeProperty(newValue:AnyObject) {
self.someProperty = newValue
}
}
En el caso particular en que desee invocar willSet
o didSet
dentro de init
para una propiedad disponible en su superclase, puede simplemente asignar su propiedad súper directamente:
override init(frame: CGRect) {
super.init(frame: frame)
// this will call `willSet` and `didSet`
someProperty = super.someProperty
}
Tenga en cuenta que la solución de Charlesism con un cierre siempre funcionaría también en ese caso. Entonces mi solución es solo una alternativa.
Esto funciona si haces esto en una subclase
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()
En a
ejemplo, didSet
no se desencadena. Pero en el ejemplo b
, didSet
se desencadena, porque está en la subclase. Tiene que hacer algo con lo que realmente significa el initialization context
, en este caso la superclass
preocupó por eso
Puedes resolverlo de manera 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
}
}
Si bien esto no es una solución, una forma alternativa de hacerlo sería usar un constructor de clase:
class SomeClass {
var someProperty: AnyObject {
didSet {
// do stuff
}
}
class func createInstance(someProperty: AnyObject) -> SomeClass {
let instance = SomeClass()
instance.someProperty = someProperty
return instance
}
}
Si usa diferir dentro de un inicializador, para actualizar cualquier propiedad opcional o actualizar propiedades no opcionales que ya ha inicializado y después de haber llamado a cualquier método de superinicio, se invocará su willSet, didSet, etc. Encuentro que esto es más conveniente que la implementación de métodos separados que usted debe hacer un seguimiento de las llamadas en los lugares correctos.
Por ejemplo:
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
}
}
}
rendirá:
I''m going to change to 3.14
Now I''m 3.14
Tuve el mismo problema y esto funciona para mí
class SomeClass {
var someProperty: AnyObject {
didSet {
doStuff()
}
}
init(someProperty: AnyObject) {
defer { self.someProperty = someProperty }
}
func doStuff() {
// do stuff now that someProperty is set
}
}