2011-10-22 11 views
6

Tengo un controlador de vista que deseo inicializar con pereza, y una vez inicializado, use la misma copia cuando sea posible (no uso un singleton porque finalmente quiero eliminarlo de la memoria) , utilizo el captador de hacerlo, mi código siguiente aspecto:Inicialización lenta de seguridad de subprocesos en iOS

@property (retain) UIViewController *myController 

... 

@synthesize myController = _myController; 


... 


- (UIViewController *)myController 
{ 
    if (!_myController) {         // Evaluation 
     _myController = [[MyViewController alloc] init]; // Object Creation 
    } 
    return _myController; 
} 

esto funciona, pero no es seguro para subprocesos, y si más de un hilo como resultado true antes de crear el objeto, voy a tener una pérdida de memoria Una solución que he intentado es sincronizar el código, pero no estoy seguro de la forma correcta de hacerlo.

Esto parece funcionar, (lockForMyController es un NSString sencilla) pero hace que esta sección del código mucho más lento:

- (UIViewController *)myController 
{ 
    @synchronized(self.lockForMyController){ 
     if (!_myController) { 
      _myController = [[MyViewController alloc] init]; 
     } 
    } 
    return _myController; 
} 

Me preguntaba si hay alguna otra forma de lograr un vago inicializado, hilo seguro, propiedad?

Respuesta

10

esta solución funciona

Tenga en cuenta que esta solución sólo funciona si se accede a myController sobre un fondo enhebrar la primera vez. Bloqueará si se llama al hilo principal.

Quiere usar gcd. La clave es serializar la creación del objeto, de modo que, independientemente de los hilos que comiencen el bloque, siempre solo se creará exactamente una vez.

- (UIViewController *)myController 
    if (_myController == nil) { 
     dispatch_sync(dispatch_get_main_queue(),^{ if (_myController == nil) _myController = [[MyViewController alloc] init]; }); 
    } 
    return _myController; 
} 

En este caso, incluso si varios subprocesos ejecutan el bloque, la ejecución del bloque es de serie en el hilo principal y sólo una vez MyViewController se pueden crear.

No verá un golpe de rendimiento aquí a menos que el objeto sea nulo.

Dado que la propiedad es implícitamente atómica, eso significa que en el colocador el valor se liberará automáticamente. Esto debería hacer que sea adecuado para mezclarse con su obtención personalizada, ya que liberará automáticamente cualquier cambio de valor en _myController.

http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW2

Sin embargo, aún puede entrar en una condición de carrera en la que está configurando el valor en un hilo, pero para acceder a él en otra. Cada vez que establezca el valor, probablemente desee asegurarse de hacer algo como esto:

dispatch_sync (dispatch_get_main_queue(),^{self.myController = {newValueOrNil}});

Esto se asegurará de serializar sus llamadas a métodos setter sin tener que reinventar la rueda para los setters atómicos, lo que es muy difícil de hacer bien.

Esta solución no funciona

Desea utilizar mcd.

http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_once

ver este post sobre embarazos únicos. Sé que no quieres un singleton, pero esto demuestra cómo usar el método. Puedes adaptarlo fácilmente.

Create singleton using GCD's dispatch_once in Objective C

+0

Tengo problemas para adaptarlo. Puedo hacer que funcione como un singleton, pero luego tengo problemas cuando uso '[_myController release]; _myController = nil; 'y luego trato de crearlo de nuevo, ya que no puedo restablecer la variable' static dispatch_once_t once'. – Yamanqui

+0

Hmm déjame actualizar mi pregunta con una sugerencia que debería funcionar. – logancautrell

+0

Muchas gracias, la solución actualizada funciona perfectamente. – Yamanqui

Cuestiones relacionadas