2015-10-16 1 views
0

Nous avons eu ce problème étrange. Lorsque nous avons instancié un objet, nous instancions également une propriété qui appartient à cet objet:Lorsqu'un objet est en train d'être instancié, comment un ACCÈS BAD peut se produire lors de l'envoi d'un message NSKeyValueNotifyObserver à un objet désalloué

-(instancetype)init 
{ 
    self = [super init]; 
    if (self) { 
    [self setDocument]; 
    } 
    return self; 
} 

-(void)setDocument: 
{ 
    _flatGraphicsArrayController = [[NSArrayController alloc] initWithContent:doc.flattenedObjects]; 
} 

... et parfois un EXC_BAD_ACCESS passe au milieu de _flatGraphicsArrayController

La pile d'appel:
enter image description here

Ce blocage a été déterminé comme étant causé par l'envoi de ce message NSKeyValueNotifyObserver à un objet désalloué, un objet qui semble observer les modifications apportées à flatGraphicsArrayController

Pour moi, c'est très déroutant car l'objet qui possède cette propriété est juste instancié, alors comment pourrait-on observer des changements dans la propriété?

Quelqu'un a-t-il été enregistré pour observer une adresse de mémoire spécifique (si c'est ainsi que cela fonctionne), puis le flatGraphicsArrayController a pris cet espace en mémoire, alors que l'observateur a été désalloué?

Répondre

2

Un objet (Object1) a été ajouté en tant qu'observateur à un autre objet (Object2). Quelque temps après cela, Object1 et Object2 ont été désalloués, mais rien n'a jamais enlevé Object1 en tant qu'observateur de Object2. La relation des observateurs de valeurs-clés est conservée en dehors de l'objet (parce que lorsque KVO a été ajouté, aucune nouvelle variable d'instance n'a pu être ajoutée à NSObject pour des raisons de compatibilité binaire, donc elle doit stocker son état dans une table annexe).

KVO devrait s'en plaindre au moment de la désallocation d'Object1. Vérifiez le journal de la console.

Quoi qu'il en soit, à un moment ultérieur, vous créez votre instance de NSArrayController. Il arrive d'occuper la même adresse que Object2. Cela signifie qu'il correspond aux informations internes de KVO sur la relation d'observation entre Object1 et Object2. Donc, efficacement, l'Object1 défunte observe maintenant votre contrôleur de tableau. Lorsque ses propriétés sont modifiées, il envoie des notifications de modification KVO à Object1. Bien sûr, Object1 n'existe plus. Selon que son adresse a été réutilisée et si cette adresse est l'adresse de base d'un nouvel objet ou des points quelque part en son sein, le résultat peut être un accident ou silencieux. Pour corriger cela, vous devez toujours supprimer les observations KVO avant que l'objet observé ou observateur ne soit libéré.

+0

Merci pour la réponse; Voilà à quoi ressemblait le problème. Que se passe-t-il lorsqu'un objet d'un type différent occupe l'espace mémoire de l'ancien Object2? –

+0

De rien. Je ne suis pas sûr de ce que vous demandez. Il est fort probable que "un objet d'un type différent occupe l'espace mémoire de l'ancien Object2" dans ce cas. C'est le but. –

+0

Ainsi, le système KVO ne se soucie pas de l'objet observé: s'il est libéré et remplacé par un objet de type différent, et que ce nouvel objet change, il envoie toujours des notifications? par exemple, quelque chose observe un objet Person. La personne est libérée. Un objet Chien remplace sa place en mémoire. L'objet chien change, l'observateur original reçoit-il une notification? Ou l'observateur original ne recevrait-il la notification que si l'objet Personne était remplacé par une autre personne? –