variable strong stored lazy swift

strong - Lazy loading Propiedades en swift



variable lazy (7)

Swift 3.0

Prefiero este estilo en línea.

lazy var myLabel: UILabel = self.createMyLabel() private func createMyLabel() -> UILabel { let mylabel = UILabel() // ... return mylabel }

Estoy tratando de entender el lenguaje Swift. Un patrón común cuando se construyen vistas en el código con Objective-C es anular las propiedades de la interfaz de usuario y cargarlas de la manera más sencilla:

@property(nonatomic, strong) UILabel *myLabel; - (UILabel *)myLabel { if (!_myLabel) { _myLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 75.0f, 320.0f, 20.0f)]; [_myLabel setFont:[UIFont subHeadlineFont]]; [_myLabel setTextColor:[UIColor subHeadlineColor]]; [_myLabel setText:@"Hello World"]; } return _myLabel; } - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.myLabel]; }

Esto permite que la configuración de los elementos UIE sea independiente dentro de su configuración, pero no da como resultado la reconfiguración de cada elemento.

Parece que no tenemos acceso a la tienda de respaldo en Swift y la palabra clave @lazy realidad no tiene la misma semántica.

Tengo curiosidad si alguien ha identificado un patrón similar en Swift que le permite a uno mantener la configuración de variables y constantes junto con su declaración en una forma sintáctica clara que no resulta en una reconfiguración cada vez.


Al igual que una variante de la respuesta de Christian Otkjær, también es posible asignar un método de clase al @lazy var:

class MyClass { @lazy var myLabel : UILabel = MyClass.newLabel() class func newLabel() -> UILabel { var temporaryLabel : UILabel = UILabel() ... return temporaryLabel } }

En realidad es lo mismo que usar un cierre, pero en caso de que haya demasiadas líneas de código en el cierre, es una opción colocar el código en un método de clase en otro lugar después de la declaración de todas las propiedades y métodos de inicialización.


Apple parece estar haciéndolo de manera diferente ... Si creo un nuevo proyecto en Xcode y agrego Core Data, hay un ejemplo de esto en AppDelegate.swift :

// Returns the managed object model for the application. // If the model doesn''t already exist, it is created from the application''s model. var managedObjectModel: NSManagedObjectModel { if !_managedObjectModel { let modelURL = NSBundle.mainBundle().URLForResource("MyApp", withExtension: "momd") _managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL) } return _managedObjectModel! } var _managedObjectModel: NSManagedObjectModel? = nil

Sin embargo, esto me parece que la variable se crea en la inicialización, sin embargo, solo se lee posteriormente y @lazy parece una implementación más agradable. ¿Alguna idea?

Así que probé esto:

class TestClass { @lazy var myLabel : UILabel = { var temporaryLabel : UILabel = UILabel() return temporaryLabel }() var testLabel: UILabel { if !_testLabel { _testLabel = UILabel() } return _testLabel! } var _testLabel: UILabel? = nil func test () { println(myLabel) println(self.testLabel) } }

Y ambos, de hecho, solo se crean de forma perezosa. Como @bradlarson señala en Twitter :

@runmad Lo único que su enfoque conserva es el estado de solo lectura de la propiedad. @lazy no se puede usar con let, que es un problema.


Creo que una propiedad lazy inicializada con un cierre funcionaría:

lazy var myLabel: UILabel = { var temporaryLabel: UILabel = UILabel() ... return temporaryLabel }()

Cuando leí "The Swift Programming Language" (Ejemplo de tablero de ajedrez), el cierre solo se evalúa una vez).


Esta es más o menos la versión Swift como su ejemplo de ObjectiveC. (simplificado para usar un Int lugar de una vista)

class Foo { var _value: Int? var value: Int { get { if !_value { _value = 123 } return _value! } } } Foo().value //-> 123

Aunque no es muy bonito.


Puede proporcionar un cierre en su variable @lazy para declarar cómo se debe crear:

class Blah { @lazy var label: () -> UILabel = { var view:UILabel = UILabel(); //Do stuff here return view; } }


class Thingy { init(){ println("making a new Thingy") } } var thingy = { Thingy(); }() println("/(self.thingy)") println("/(self.thingy)")

El mensaje de registro "hacer un nuevo Thingy" aparece solo una vez, lo que demuestra que solo se creó un Thingy: el cierre se realizó solo una vez, concretamente para inicializar esta propiedad. Esto es efectivamente lo que estás describiendo. Todo lo que tiene que hacer es agregar más al cierre para configurarlo como el objeto devuelto.

Si usted hace el var @lazy y comenta las declaraciones println , no se crea Thingy, demostrando que la pereza hace lo que se pretende; sin embargo, podría omitir esto, ya que sabe que la etiqueta siempre se necesitará desde el principio. El objetivo de @lazy es evitar que se @lazy el cierre a menos que se llame al captador, pero siempre se llamará al captador para que no tenga sentido en su situación.