sale para liberar lanzamiento fecha descargar desbloquear cuando cualquier compañia como apple iphone objective-c cocoa-touch

iphone - para - ¿Cuándo se libera un objeto asociado?



ios 12 iphone 6 (4)

Incluso más grande que tu problema de de- -dealloc es este:

UIKit no es compatible con KVO

No se ha hecho ningún esfuerzo para hacer que las clases de UIKit sean de valor-clave observables. Si alguno de ellos lo es , es completamente fortuito y está sujeto a un rompimiento por capricho de Apple. Y sí, trabajo para Apple en el marco de UIKit.

Esto significa que tendrá que encontrar otra forma de hacerlo, probablemente cambiando ligeramente el diseño de su vista.

Estoy adjuntando el objeto B a través de una referencia asociativa al objeto A. El Objeto B observa algunas propiedades del objeto A a través de KVO.

El problema es que el objeto B parece desasignarse después del objeto A, lo que significa que es demasiado tarde para eliminarse como observador KVO del objeto A. Lo sé porque obtengo excepciones NSKVODeallocateBreak, seguidas de bloqueos EXEC_BAD_ACCESS en dealloc del objeto B.

¿Alguien sabe por qué el objeto B se desasigna después del objeto A con OBJC_ASSOCIATION_RETAIN? ¿Los objetos asociados se liberan después de la desasignación? ¿Se vuelven a lanzar automáticamente? ¿Alguien sabe de una manera de alterar este comportamiento?

Estoy tratando de agregar algunas cosas a una clase a través de categorías, por lo que no puedo anular ningún método existente (incluido dealloc), y no quiero complicarme demasiado con el swizzling. Necesito alguna forma de desasociar y liberar el objeto B antes de que el objeto A sea desasignado.

EDITAR - Aquí está el código que estoy tratando de poner en práctica. Si los objetos asociados se liberaron antes de que UIImageView se desasignara por completo, todo esto funcionaría. La única solución que estoy viendo es usar mi propio método dealloc, y devolver el original para llamarlo. Eso se pone muy complicado sin embargo.

El objetivo de la clase ZSPropertyWatcher es que KVO requiere un método de devolución de llamada estándar, y no quiero reemplazar UIImageView, en caso de que utilice uno.

UIImageView + Loading.h

@interface UIImageView (ZSShowLoading) @property (nonatomic) BOOL showLoadingSpinner; @end

UIImageView + Loading.m

@implementation UIImageView (ZSShowLoading) #define UIIMAGEVIEW_SPINNER_TAG 862353453 static char imageWatcherKey; static char frameWatcherKey; - (void)zsShowSpinner:(BOOL)show { if (show) { UIActivityIndicatorView *spinnerView = (UIActivityIndicatorView *)[self viewWithTag:UIIMAGEVIEW_SPINNER_TAG]; if (!spinnerView) { spinnerView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease]; spinnerView.tag = UIIMAGEVIEW_SPINNER_TAG; [self addSubview:spinnerView]; [spinnerView startAnimating]; } [spinnerView setEvenCenter:self.boundsCenter]; } else { [[self viewWithTag:UIIMAGEVIEW_SPINNER_TAG] removeFromSuperview]; } } - (void)zsFrameChanged { [self zsShowSpinner:!self.image]; } - (void)zsImageChanged { [self zsShowSpinner:!self.image]; } - (BOOL)showLoadingSpinner { ZSPropertyWatcher *imageWatcher = (ZSPropertyWatcher *)objc_getAssociatedObject(self, &imageWatcherKey); return imageWatcher != nil; } - (void)setShowLoadingSpinner:(BOOL)aBool { ZSPropertyWatcher *imageWatcher = nil; ZSPropertyWatcher *frameWatcher = nil; if (aBool) { imageWatcher = [[[ZSPropertyWatcher alloc] initWithObject:self keyPath:@"image" delegate:self callback:@selector(zsImageChanged)] autorelease]; frameWatcher = [[[ZSPropertyWatcher alloc] initWithObject:self keyPath:@"frame" delegate:self callback:@selector(zsFrameChanged)] autorelease]; [self zsShowSpinner:!self.image]; } else { // Remove the spinner [self zsShowSpinner:NO]; } objc_setAssociatedObject( self, &imageWatcherKey, imageWatcher, OBJC_ASSOCIATION_RETAIN ); objc_setAssociatedObject( self, &frameWatcherKey, frameWatcher, OBJC_ASSOCIATION_RETAIN ); } @end

ZSPropertyWatcher.h

@interface ZSPropertyWatcher : NSObject { id delegate; SEL delegateCallback; NSObject *observedObject; NSString *keyPath; } @property (nonatomic, assign) id delegate; @property (nonatomic, assign) SEL delegateCallback; - (id)initWithObject:(NSObject *)anObject keyPath:(NSString *)aKeyPath delegate:(id)aDelegate callback:(SEL)aSelector; @end

ZSPropertyWatcher.m

@interface ZSPropertyWatcher () @property (nonatomic, assign) NSObject *observedObject; @property (nonatomic, copy) NSString *keyPath; @end @implementation ZSPropertyWatcher @synthesize delegate, delegateCallback; @synthesize observedObject, keyPath; - (id)initWithObject:(NSObject *)anObject keyPath:(NSString *)aKeyPath delegate:(id)aDelegate callback:(SEL)aSelector { if (!anObject || !aKeyPath) { // pre-conditions self = nil; return self; } self = [super init]; if (self) { observedObject = anObject; keyPath = aKeyPath; delegate = aDelegate; delegateCallback = aSelector; [observedObject addObserver:self forKeyPath:keyPath options:0 context:nil]; } return self; } - (void)dealloc { [observedObject removeObserver:self forKeyPath:keyPath]; [keyPath release]; [super dealloc]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { [self.delegate performSelector:self.delegateCallback]; } @end


La respuesta aceptada a esta pregunta relacionada explica la línea de tiempo de desasignación de objetos. El resultado es: Los objetos asociados se liberan después de que el método dealloc del objeto original ha finalizado.


Lo que creo que está sucediendo en tu caso es esto:

1) el objeto A recibe la llamada -dealloc , después de que su conteo retenido haya pasado a 0;

2) el mecanismo de asociación asegura que el objeto B se libera (que es diferente de desasignado) en algún momento como consecuencia.

es decir, no sabemos exactamente en qué punto, pero me parece probable que este tipo de diferencia semántica sea la causa de que el objeto B sea desasignado después del objeto A; objeto A -dealloc selector no puede conocer la asociación, por lo que cuando se llama a la última versión, -dealloc se ejecuta, y solo después de eso el mecanismo de asociación puede enviar un -release al objeto B ...

también eche un vistazo a esta publicación .

también declara:

Ahora, cuando objecttoBeDeallocated es desasignado, objectWeWantToBeReleasedWhenThatHappens se enviará un mensaje de liberación automáticamente.

Espero que esto ayude a explicar lo que estás experimentando. En cuanto al resto, no puedo ser de mucha ayuda ...

EDITAR: solo para seguir con una especulación tan interesante después del comentario de DougW ...

Veo el riesgo de tener una especie de dependencia cíclica si el mecanismo de asociación se "rompió" al liberar el objeto A (para seguir con su ejemplo).

  1. si el código relacionado con la asociación se ejecutó a partir del método de publicación (en lugar de dealloc), para cada versión verificaría si el objeto "propietario" (objeto A) tiene un conteo retenido de 1; de hecho, en tal caso, usted sabe que al disminuir su conteo de retención desencadenaría el deslocalización, por lo tanto, antes de hacerlo, primero liberaría el objeto asociado (el objeto B en su ejemplo);

  2. pero ¿qué sucedería en caso de que el objeto B también fuera a su vez "dueño" de un tercer objeto, digamos C? lo que sucedería es que en el momento en que se solicita la liberación del objeto B, cuando el conteo de retención del objeto B es 1, se liberaría C;

  3. ahora, considere el caso de que el objeto C era "dueño" de la primera de esta secuencia, el objeto A. si, al recibir el lanzamiento anterior, C tenía un conteo de retención de 1, primero intentaría y liberaría su objeto asociado, que es un;

    1. pero el recuento de liberaciones de A sigue siendo 1, por lo que se enviará otro lanzamiento a B, que todavía tiene un recuento de retención de 1; y así sucesivamente, en un bucle.

Si, por otro lado, envía el lanzamiento del -dealloc, esa dependencia cíclica no parece posible.

Es bastante artificial y no estoy seguro de que mi razonamiento sea correcto, así que no dude en comentarlo ...


objc_getAssociatedObject() para una asociación OBJC_ASSOCIATION_RETAIN devuelve un objeto liberado automáticamente. ¿Podría llamarlo antes en el mismo ámbito de ciclo de cicloreproceso / autorrelease como objeto A está desasignado? (Probablemente pueda probar esto rápidamente cambiando la asociación a NONATOMIC ).