Pregunta

He estado usando bloques durante algún tiempo ahora, pero siento que hay cosas que echo de menos acerca de la gestión de la memoria en tanto el ARC y no-ARCO entornos.Siento que la comprensión más profunda me hará nula muchas pérdidas de memoria.

AFNetworking es mi principal uso de Bloques en una aplicación en particular.La mayoría de las veces, dentro de un controlador de finalización de una operación, yo hago algo como "[auto.myArray addObject]".

En tanto el ARC y no-ARCO habilitado entornos "auto" será retenido de acuerdo a este artículo de Apple.

Eso significa que cada vez que un bloque de finalización de un AFNetworking de operación de la red se llama, yo es retenido dentro de ese bloque, y se liberan cuando ese bloque sale del ámbito.Creo que esto se aplica tanto al ARCO y no de ARCO.He corrido tanto las Filtraciones de la herramienta y el Analizador Estático para que yo pueda encontrar alguna pérdida de memoria.Ninguno mostró ninguna.

Sin embargo, no fue hasta hace poco que me topé con una advertencia de que no podía averiguar.Yo estoy usando el ARCO en este ejemplo en particular.

Tengo dos variables de instancia que indican la finalización y el fracaso de una operación de la red de

@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;

En algún lugar en el código, hago esto:

[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
                                                    responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
            _failureBlock(error);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"nothing");
        }];

Xcode se queja acerca de la línea que llama a la failureBlock, con el mensaje de "Capturar "auto" fuertemente en este bloque es probable que resulte en una retener ciclo.Creo Xcode es el correcto:el fracaso del bloque conserva auto, y el auto tiene su propia copia de la cuadra, así que ninguno de los dos va a ser desasignado.

Sin embargo, tengo las siguientes preguntas/observaciones.

1) Si yo cambio _failureBlock(error) "auto.failureBlock(error)" (sin las comillas) el compilador deja de quejarse.¿Por qué es eso?Es esto una pérdida de memoria que el compilador se pierde?

2) En general, ¿cuál es la mejor práctica para el trabajo con los bloques en tanto el ARC y no-ARCO habilitado ambientes cuando se utiliza los bloques de variables de instancia?Parece que en el caso de finalización y el fracaso de los bloques en AFNetworking, los dos bloques se no las variables de instancia, por lo que probablemente no entran en la categoría de conservar los ciclos que he descrito anteriormente.Pero cuando el uso de progreso bloques en AFNetworking, ¿qué se puede hacer para evitar retener ciclos como el de arriba?

Me encantaría escuchar los pensamientos de otras personas en el ARCO y no-ARCO con bloques y problemas/soluciones con la gestión de memoria.Me parece que estas situaciones propensas a errores y siento un poco de discusión sobre este tema es necesario aclarar las cosas.

No sé si importa, pero yo uso Xcode 4.4 con la última LLVM.

¿Fue útil?

Solución

1) Si cambio _FailureBlock (error) a "Self.FailureBlock (error)" (Sin cotizaciones) El compilador deja de quejarse. ¿Porqué es eso? Es esto ¿Una pérdida de memoria se pierde el compilador?

El ciclo de retención existe en ambos casos. Si está dirigido a iOS 5+, puede pasar una referencia débil a uno mismo:

__weak MyClass *weakSelf;
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
    if (weakSelf.failureBlock) weakSelf.failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"nothing");
}];

Ahora no se retendrá, y si se desalicia antes de que se invoque la devolución de llamada, la devolución de llamada es un NO-OP. Sin embargo, es posible que pueda estar en proceso de desascripción, mientras que la devolución de llamada se invoca en un hilo de fondo, por lo que este patrón puede crear accidentes ocasionales.

2) En general, ¿cuál es la mejor práctica para trabajar con bloques en ambos Entornos de arco y no arco habilitados cuando se usan bloques que son ¿variables de instancia? Parece que en el caso de la finalización y el fracaso. Bloques en AFNetworking, esos dos bloques no son variables de instancia, por lo que Probablemente no caigan en la categoría de retener los ciclos que yo descrito arriba. Pero cuando se usan bloques de progreso en AFNetworking, ¿Qué se puede hacer para evitar retener los ciclos como la anterior?

la mayor parte del tiempo, creo es mejor no hacerlo Bloques de la tienda en las variables de ejemplo . Si, en su lugar, devuelve el bloque de un método en su clase, aún tendrá un ciclo de retención, pero solo existe desde el momento en que se invoca el método hasta la hora en que se libera el bloque. Por lo tanto, evitará que su instancia se establezca durante la ejecución del bloque, pero el ciclo de retención termina cuando se libera el bloque:

-(SFCompletionBlock)completionBlock {
    return ^(AFHTTPRequestOperation *operation , id responseObject ) {
        [self doSomethingWithOperation:operation];
    };
}

[self.operation setCompletionBlockWithSuccess:[self completionBlock]
                                      failure:[self failureBlock]
];

Otros consejos

Eso significa que cada vez que un bloque de finalización de un AFNetworking red la operación se llama, yo es retenido dentro de ese bloque, y liberado cuando ese bloque sale del ámbito.

No, self es retenido por el bloque cuando el bloque se crea.Y es liberado cuando el bloque se cancela la asignación.

Creo Xcode es el correcto:el fracaso del bloque conserva auto, y el auto mantiene su propia copia de la cuadra, por lo que ninguno de los dos será desasignado.

El bloque en cuestión, que conserva la self es la culminación de bloque pasa a setCompletionBlockWithSuccess. self no contener una referencia a este bloque.Más bien, self.operation (es de suponer que algún tipo de NSOperation) conserva los bloques mientras se está ejecutando.Así que ahí está temporalmente un ciclo.Sin embargo, cuando la operación se lleva a cabo la ejecución, el ciclo se ha roto.

1) Si yo cambio _failureBlock(error) "auto.failureBlock(error)" (sin comillas) el compilador deja de quejarse.¿Por qué es eso?Es este una pérdida de memoria que el compilador se pierde?

No debe haber ninguna diferencia. self es capturado en ambos casos.El compilador no está garantizada para la captura de todos los casos de conservar los ciclos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top