objective-c - sincrono - qué es síncrono y asíncrono
iOS y ARC: ¿Cómo retenerse durante las operaciones asíncronas? (4)
Es la primera vez que estoy jugando con iOS5 y ARC. Hasta ahora, todo bien, funciona, pero me he encontrado con algún tipo de problema.
Tengo un UIStoryboardSegue
personalizado en el que utilizo Facebook Connect (u otros servicios) para registrar al usuario en mi aplicación. En pocas palabras, debe hacer lo siguiente:
- El usuario hace clic en el botón
- Botón dispara el Segue
- El segmento inicia el inicio de sesión asíncrono pero no presiona inmediatamente el controlador de vista
- Si, y solo si el inicio de sesión es exitoso, el segmento empuja el controlador de vista
Lo que sucede en su lugar, es que el inicio de sesión se inicia, pero ARC libera inmediatamente la sesión antes de que tenga alguna oportunidad de completar.
Pensé en un hack rápido para evitar esto:
@interface BSLoginSegue() {
__strong BSLoginSegue *_retained_self;
}
@end
// Stuff...
// Other stuff...
- (void) perform {
login();
_retained_self = self;
}
- (void) loginServiceDidSucceed:(BSLoginService *)svc {
...
_retained_self = nil;
}
La cuestión es que realmente es un truco , así que me preguntaba si habría alguna otra forma más elegante de hacer lo mismo.
La idea de que una clase debería tener que mantenerse a sí misma sugiere que podría haber un problema de diseño. Cuando un objeto se retiene a sí mismo, no queda claro quién es el propietario o quién podría tener una referencia a él, y el riesgo de una fuga es alto.
¿Qué clase es la responsable de presentar el segue? ¿Es la misma clase que contiene el botón? Esta clase debe conservar el segmento, presentar el segmento y luego liberar el segmento cuando / si el segmento se completa.
Sin más información sobre la jerarquía del controlador de vista, es difícil dar consejos específicos. Pero mi primera reacción es sugerir que el controlador de vista que está decidiendo presentar el segmento o no debería tener una propiedad sólida en el segmento. La sesión segue subclasificada puede definir un protocolo que la clase presentadora puede cumplir para que se le avise cuándo se debe anular / liberar la sesión.
Si usa Grand Central Dispatch (GCD) para la concurrencia (¡lo que debería hacer, es increíble!), Al colocar una referencia a su objeto en un bloque de Objective-C y pasarlo a GCD, el bloque lo retendrá automáticamente hasta después El bloque se ha ejecutado y se ha liberado.
Sin saber exactamente cómo estás haciendo tus operaciones asíncronas, es difícil dar una respuesta definitiva, pero al usar bloques y GCD no tendrás que preocuparte por esto en absoluto. El bloque se encargará de retener los objetos a los que hace referencia y ARC hará el resto.
Parece que debe estar almacenando una referencia a su subclase UIStoryboardSegue
algún lugar, para llamar a loginServiceDidSucceed:
en ella, así que quizás solo haga que una referencia sólida funcione. Una vez más, lo ideal es hacer referencia a él desde un bloque (como un bloque de finalización cuando el inicio de sesión es exitoso). Recomendaría adaptar su código de inicio de sesión para usar bloques para las devoluciones de llamadas de éxito / fracaso.
Simplemente agregue y elimine self
en / desde una matriz que sea un miembro de datos de self
de self
siguiente manera:
@interface MyClass
{
NSMutableArray* _selfRetains;
}
@end
@implementation MyClass
-(id)retainSelf
{
[_selfRetains addObject:self];
return self;
}
-(void)releaseSelf
{
[_selfRetains removeLastObject];
}
@end
Luego, reemplace [self retain]
con [self retainSelf]
y [self release]
con [self releaseSelf]
.
Si bien las otras respuestas son correctas y, por lo general, debe evitar un diseño que requiera que una clase se retenga, esta solución no requiere que cambie significativamente el diseño de su aplicación.
Singleton puede ser su elección si necesita conservar su propia instancia en una operación asíncrona.