iphone - metodos - no se puede invocar un tipo no delegado c#
Liberar un objeto delegante en su método de devolución de llamada de delegado (4)
Al igual que Michal dijo que no hay absolutamente ninguna buena razón para liberar el objeto del administrador para ahorros de memoria. Además, al igual que JeremyP dijo, sería un patrón completamente incorrecto y un diseño inteligente liberar un objeto dentro de otra función que solo reciba ese objeto. Va en contra de todas las reglas.
Sin embargo, lo que sería correcto es simplemente detener las actualizaciones y establecer el delegado de administradores en cero como ya está haciendo. Entonces, lo único que necesita eliminar es la línea [versión de administrador].
Supongo que está creando un administrador en un ámbito local y, por lo tanto, está tratando de averiguar cómo asegurarse de que el administrador sea liberado. Lo correcto a hacer aquí sería crear un administrador como una variable de instancia de su clase y luego liberarlo en la clase dealloc.
Estoy tratando de averiguar cuál es la práctica recomendada para la siguiente situación. Ciertos objetos, como CLLocationManager o MKReverseGeocoder, envían sus resultados de forma asíncrona a un método de devolución de llamada delegada. ¿Está bien lanzar esa instancia de CLLocationManager o MKReverseGeocoder (o la clase que sea) en el método de devolución de llamada? El punto es que ya no necesita ese objeto alrededor, por lo que le dice que deje de enviar actualizaciones, establezca su delegado en nulo y libere el objeto.
Pseudo código:
@interface SomeClass <CLLocationManagerDelegate>
...
@end
@implementation SomeClass
...
- (void)someMethod
{
CLLocationManager* locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// Do something with the location
// ...
[manager stopUpdatingLocation];
manager.delegate = nil;
[manager release];
}
@end
Me pregunto si este patrón de uso se considera siempre correcto, si nunca se considera correcto o si depende de la clase.
Hay un caso obvio en el que liberar el objeto delegante sería incorrecto y es si tiene que hacer cosas después de haber notificado al delegado. Si el delegado libera el objeto, su memoria puede sobrescribirse y la aplicación se bloquea. (Eso parece ser lo que sucede en mi aplicación con CLLocationManager en una circunstancia particular, ambas solo en el simulador. Estoy tratando de averiguar si se trata de un error del simulador o si lo que estoy haciendo es fundamentalmente defectuoso).
He estado buscando y no puedo encontrar una respuesta concluyente a esto. ¿Alguien tiene una fuente autorizada que pueda responder esta pregunta?
Esta es una muy buena pregunta, esperé unas horas con la esperanza de que alguien diera una respuesta suficiente, pero como nadie respondió, lo intentaré. Primero, comentaré su enfoque, luego intentaré sugerir cómo abordaría esto.
Definitivamente es una muy mala idea liberar, por lo tanto, desasignar un objeto de su delegado. Solo piense en cómo los objetos (como un CLLocationManager) llaman a sus delegados, simplemente los llaman en el medio de algún método. Cuando finaliza la llamada a delegado, la ejecución del código vuelve a un método de un objeto que ya se ha desasignado. BAM!
Olvidemos por un momento el hecho de que esta es una mala idea. Veo dos opciones de cómo arreglar eso fácilmente. Primero, la autorelease
lugar del release
le da a un objeto un poco más de tiempo de correo no deseado: al menos sobreviviría al regresar del delegado. Eso debería ser suficiente para la mayoría de los casos, al menos si el autor de la API hizo bien su trabajo y encapsuló la lógica detrás de la clase principal de la API (en el caso de CLLocationManager podría estar esperando que el GPS se apague ...). La segunda opción sería retrasar la publicación ( performSelector:withObject:afterDelay:
viene a la mente), pero eso es más como una solución para las API mal implementadas.
Entonces, si lanzarlo no es una buena idea, ¿entonces qué es?
Bueno, ¿qué gana realmente al lanzar un CLLocationManager? Liberar esos pocos bytes de memoria no evitará que su aplicación termine cuando el sistema se queda sin memoria. De todos modos, ¿es realmente solo una vez que necesita la ubicación del usuario actual?
Le sugiero que encapsule las tareas relacionadas con CLLocationManager en una clase separada, probablemente incluso un singleton; esa clase se convertiría en su delegado, y se encargaría de comunicarse con CLLocationManager e informar a su aplicación sobre los resultados (probablemente mediante el envío de NSNotification
). CLLocationManager se liberaría del dealloc de esa clase, y nunca como resultado de una devolución de llamada de delegado. stopUpdatingLocation
debería bastar, liberando pocos bytes de memoria; bueno, puede hacerlo cuando la aplicación ingresa en segundo plano, pero mientras se ejecute, la liberación de esos pocos bytes no hace ninguna mejora significativa en el consumo de memoria.
** Adición **
Es natural y correcto que un delegado tenga la propiedad de un objeto para el cual actúa como delegado. Pero el delegado no debe liberar el objeto como resultado de una devolución de llamada. Sin embargo, hay una excepción a esto, y es la devolución de llamada que le dice que el procesamiento ha terminado. Como ejemplo de esto, se encuentra NSURLConnection
de NSURLConnection
connectionDidFinishLoading:
que se indica en la documentación "El delegado no recibirá más mensajes". Puede hacer que una clase descargue un montón de archivos, cada uno con un NSURLConnection
diferente (con su clase como delegado), asignándolos Y liberándolos a medida que avanza la descarga de archivos.
El comportamiento de CLLocationManager
es diferente. Debe tener solo una instancia de CLLocationManager en su programa. Esa instancia es administrada por algún código, probablemente un singleton, uno que podría lanzarse cuando la aplicación entra en segundo plano, y se reinicializa cuando se despierta. La vida útil de CLLocationManager
sería la misma que la de su clase de gestión, que también actúa como delegado.
No. Ese patrón siempre se considera incorrecto. Se rompen las Reglas de Gestión de la Memoria del Cacao . El objeto administrador se pasó como un parámetro. No lo obtuvo por nuevo, asignar o copiar, ni lo retuvo. Por lo tanto no debes soltarlo.
Otra razón por la que su patrón es una mala idea es que para algo como un CLLocationManager, por lo general, quiere decirle que deje de recibir actualizaciones si la pantalla se pone en reposo: solo puede hacerlo si mantiene una referencia en algún lugar que pueda indicar. iniciar / detener Y si está manteniendo una referencia, entonces también puede gestionarla por completo.