6

Tengo una propiedad de sólo lectura isFinished en mi archivo de interfaz:Asignación a Ivar en un bloque a través de puntero débil

typedef void (^MyFinishedBlock)(BOOL success, NSError *e); 

@interface TMSyncBase : NSObject { 
    BOOL isFinished_; 
} 

@property (nonatomic, readonly) BOOL isFinished; 

y quiero ponerlo en YES en un bloque en algún momento posterior, sin crear un ciclo de retener a self:

- (void)doSomethingWithFinishedBlock:(MyFinishedBlock)theFinishedBlock { 
    __weak MyClass *weakSelf = self; 
    MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
     [weakSelf willChangeValueForKey:@"isFinished"]; 
     weakSelf -> isFinished_ = YES; 
     [weakSelf didChangeValueForKey:@"isFinished"]; 
     theFinishedBlock(success, e); 
    }; 

    self.finishedBlock = finishedBlockWrapper; // finishedBlock is a class ext. property 
} 

estoy seguro de que esta es la forma correcta de hacerlo. ¿Este código se fugará, o se romperá, o está bien? Tal vez hay una manera más fácil que he pasado por alto?

+2

lo digo, se puede usar '__weak typeof (auto) * = weakSelf auto;' –

+0

fresco, eso es útil! – manmal

+4

Pequeña corrección de la declaración general '__weak typeof (self) weakSelf = self;' typeof (self) ya es un puntero. – allprog

Respuesta

5

Pasando variable de bloque puede ser nulo, y comprueba antes de llamar o añadir afirman en el arranque de la función o se bloqueará

Puesto que usted no está reteniendo mismo y suponemos que se ejecuta una tarea de largo en subproceso en segundo plano por el el tiempo en que se ejecuta el código weakelfelf puede ser nulo (con suerte está utilizando ARC y 5.0 por lo que ha niled referencias débiles).

Si no tiene referencias reales débiles (< 5.0, sin ARC, el compilador aún aceptaría __weak pero no importaría) esto provocaría la falla.

También accediendo a ivar usando '->' dará lugar a la falla si el puntero del objeto es nulo, por lo que debe asegurarse de que no ocurra.

Incluso si hace el código como dasblinkenlight escribió puede fallar si weakSelf será nulo en este momento, digamos que despacha el bloque en el hilo de fondo y luego el objeto se libera antes de que se ejecute el bloque, esto hace que weakelfelf lo acceda al usar '->' provocará un bloqueo. En ese caso me gustaría modificar el código de la siguiente manera:

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    MyClass *strongSelf = weakSelf; 
    //! whatever task you want executed 
    strongSelf.isFinished = YES; 
    theFinishedBlock(success, e); 
}; 

También podría probar si weakSelf es nula para evitar tarea costosa de ejecución si no tiene sentido (objeto ya está destruida). Pero esto depende del caso de uso.

Pero también hay otro caso que debe tener en cuenta al programar con bloques, por ejemplo: Puede tener una instancia de objeto de trabajo que es solo la función de ejecutar alguna tarea en segundo plano, en ese caso este código podría fallar porque crearía una nueva tarea y podría desasignarse antes de que el bloque se ejecute en el hilo de fondo, en ese caso debe retenerse y no retener el bloque en el objeto (esto evitará que se retenga el ciclo).

+0

gracias! sí, es iOS5, gracias a Dios. – manmal

+0

isFinished es una propiedad de solo lectura, por lo que no quiero que '' 'strongSelf.isFinished = YES''' funcione .. está allí solo para KVO – manmal

+1

Especificar es una asignación normal en la categoría privada, esto hará que sea posible en su código de clase pero solo fuera de él, esto también omitirá las notificaciones KVO manuales innecesarias. –

0

Una pequeña solución es crear un método y dejar que el compilador lo maneje por usted. Funciona bien, pero no estoy seguro si es la forma correcta. ¿Alguien puede decir si es correcto?

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    [weakSelf makeIsFinishedYes]; 
}; 

- (void)makeIsFinishedYes 
{ 
    isFinished_ = YES; 
} 
Cuestiones relacionadas