Estoy un poco confundido sobre el uso de bloques en Objective-C. Actualmente uso ARC y tengo bastantes bloques en mi aplicación, actualmente siempre me refiero en self
lugar de su referencia débil. ¿Puede ser esa la causa de que estos bloques self
retengan y eviten que sean desalojados? La pregunta es, ¿debería usar siempre una weak
referencia de self
en un bloque?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
ios
iphone
objective-c
automatic-ref-counting
weak-references
el crítico
fuente
fuente
Respuestas:
Ayuda a no centrarse en parte
strong
oweak
en la discusión. En cambio, concéntrate en la parte del ciclo .Un ciclo de retención es un ciclo que ocurre cuando el Objeto A retiene el Objeto B, y el Objeto B retiene el Objeto A. En esa situación, si cualquiera de los objetos se libera:
Por lo tanto, esos dos objetos permanecerán en la memoria durante toda la vida del programa, aunque deberían, si todo funcionara correctamente, ser desasignado.
Entonces, lo que nos preocupa es retener ciclos , y no hay nada sobre los bloques en sí mismos que crean estos ciclos. Esto no es un problema, por ejemplo:
El bloque retiene
self
, peroself
no retiene el bloque. Si se libera uno u otro, no se crea ningún ciclo y todo se desasigna como debería.Donde te metes en problemas es algo como:
Ahora, su objeto (
self
) tiene unastrong
referencia explícita al bloque. Y el bloque tiene una fuerte referencia implícita aself
. Eso es un ciclo, y ahora ninguno de los objetos se desasignará correctamente.Porque, en una situación como esta,
self
por definición ya tiene unastrong
referencia al bloque, generalmente es más fácil de resolver haciendo una referencia explícitamente débilself
para que el bloque use:¡Pero este no debería ser el patrón predeterminado que sigues cuando trates con bloques que llaman
self
! Esto solo debe usarse para romper lo que de otro modo sería un ciclo de retención entre uno mismo y el bloque. Si adoptara este patrón en todas partes, correría el riesgo de pasar un bloque a algo que se ejecutó después de queself
fue desasignado.fuente
-setCompleteionBlockWithSuccess:failure:
método. Pero sipaginator
es propiedad de ellosViewController
, y estos bloques no se llaman despuésViewController
, se liberaría, usar una__weak
referencia sería el movimiento seguro (porqueself
posee lo que posee los bloques, por lo que es probable que siga existiendo cuando los bloques lo llamen a pesar de que no lo retienen). Pero eso es un montón de "si". Realmente depende de lo que se supone que debe hacer.MyObject
ySomeOtherObject
ambos son dueños del bloque. Pero debido a que la referencia del bloque vuelve aMyObject
serweak
, el bloque no es el propietarioMyObject
. Así, mientras que el bloque se garantiza que existirá mientras seaMyObject
oSomeOtherObject
existe, no hay garantía de queMyObject
existirá siempre y cuando el bloque hace.MyObject
puede ser completamente desasignado y, mientrasSomeOtherObject
exista, el bloque seguirá allí.No tiene que usar siempre una referencia débil. Si su bloqueo no se retiene, sino que se ejecuta y luego se descarta, puede capturarse con fuerza, ya que no creará un ciclo de retención. En algunos casos, incluso desea que el bloque se retenga hasta que se complete el bloque para que no se desasigne prematuramente. Sin embargo, si captura el bloque con fuerza, y dentro de sí mismo, creará un ciclo de retención.
fuente
Estoy totalmente de acuerdo con @jemmons:
Para superar este problema, se puede definir una referencia fuerte sobre el
weakSelf
interior del bloque:fuente
->
), donde desea garantizar que realmente obtuvo una referencia válida y mantenerla continuamente en todo el conjunto de operaciones, por ejemploif ( strongSelf ) { /* several operations */ }
Como Leo señala, el código que agregó a su pregunta no sugeriría un ciclo de referencia fuerte (también conocido como ciclo de retención). Un problema relacionado con la operación que podría causar un fuerte ciclo de referencia sería si la operación no se libera. Si bien su fragmento de código sugiere que no ha definido su operación como concurrente, pero si lo ha hecho, no se publicará si nunca publicó
isFinished
, o si tuvo dependencias circulares, o algo así. Y si la operación no se lanza, el controlador de vista tampoco se lanzaría. Sugeriría agregar un punto de interrupción oNSLog
en eldealloc
método de su operación y confirmar que se llama.Tu dijiste:
Los problemas del ciclo de retención (ciclo de referencia fuerte) que ocurren con los bloques son como los problemas del ciclo de retención con los que está familiarizado. Un bloque mantendrá referencias fuertes a cualquier objeto que aparezca dentro del bloque, y no liberará esas referencias fuertes hasta que se libere el bloque mismo. Por lo tanto, si las referencias de bloque
self
, o incluso solo hace referencia a una variable de instancia deself
, que mantendrá una fuerte referencia a sí mismo, eso no se resolverá hasta que se libere el bloque (o en este caso, hasta queNSOperation
se libere la subclase.Para obtener más información, consulte la sección Evitar ciclos de referencia fuertes al capturar uno mismo del documento Programación con Objective-C: Trabajar con bloques .
Si su controlador de vista aún no se está lanzando, simplemente tiene que identificar dónde reside la referencia fuerte no resuelta (suponiendo que confirmó que
NSOperation
se está desasignando). Un ejemplo común es el uso de una repeticiónNSTimer
. O algúndelegate
objeto personalizado u otro que mantiene erróneamente unastrong
referencia. A menudo puede usar instrumentos para rastrear dónde los objetos obtienen sus referencias fuertes, por ejemplo:O en Xcode 5:
fuente
Algunas explicaciones ignoran una condición sobre el ciclo de retención [Si un grupo de objetos está conectado por un círculo de relaciones fuertes, se mantienen vivos incluso si no hay referencias fuertes desde fuera del grupo.] Para obtener más información, lea el documento
fuente
Así es como puedes usar el self dentro del bloque:
// llamada del bloque
fuente