2010-11-08 9 views
24

Sono relativamente nuovo a KVO, quindi c'è una buona possibilità che io stia violando alcune regole fondamentali. Sto usando Core Data.An -observeValueForKeyPath: ofObject: change: context: il messaggio è stato ricevuto ma non gestito

La mia app si arresta in modo anomalo con il seguente messaggio: E quello che non riesco a capire è perché un CGImage venga coinvolto nell'osservazione di un valore impostato su un oggetto MeasurementPointer.

 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<CGImage 0x276fc0>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. 
Key path: measurementDescriptor 
Observed object: <MeasurementPointer: 0x8201640> (entity: MeasurementPointer; id: 0x8200410 <x-coredata://EBEE0687-D67D-4B03-8C95-F4C60CFDC20F/MeasurementPointer/p75> ; data: { 
    measurementDescriptor = "0x260fd0 <x-coredata://EBEE0687-D67D-4B03-8C95-F4C60CFDC20F/MeasurementDescriptor/p22>"; 
}) 
Change: { 
    kind = 1; 
    new = "<MeasurementDescriptor: 0x262530> (entity: MeasurementDescriptor; id: 0x260fd0 <x-coredata://EBEE0687-D67D-4B03-8C95-F4C60CFDC20F/MeasurementDescriptor/p22> ; data: {\n measurementName = Temperature;\n measurementUnits = \"\\U00b0C\";\n sortString = nil;\n})"; 
} 
Context: 0x0' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x30897ed3 __exceptionPreprocess + 114 
    1 libobjc.A.dylib      0x3002f811 objc_exception_throw + 24 
    2 CoreFoundation      0x30897d15 +[NSException raise:format:arguments:] + 68 
    3 CoreFoundation      0x30897d4f +[NSException raise:format:] + 34 
    4 Foundation       0x34a13779 -[NSObject(NSKeyValueObserving) observeValueForKeyPath:ofObject:change:context:] + 60 
    5 Foundation       0x349b6acd NSKeyValueNotifyObserver + 216 
    6 Foundation       0x349b6775 NSKeyValueDidChange + 236 
    7 Foundation       0x349ae489 -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 76 
    8 CoreData       0x3165b577 _PF_ManagedObject_DidChangeValueForKeyIndex + 102 
    9 CoreData       0x3165ac51 _sharedIMPL_setvfk_core + 184 
    10 CoreData       0x3165dc83 _svfk_0 + 10 
    11 SPARKvue       0x000479f1 -[MeasurementViewController doneAction:] + 152 
    12 CoreFoundation      0x3083f719 -[NSObject(NSObject) performSelector:withObject:withObject:] + 24 
    13 UIKit        0x31eb1141 -[UIApplication sendAction:to:from:forEvent:] + 84 
    14 UIKit        0x31f08315 -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 92 
    15 CoreFoundation      0x3083f719 -[NSObject(NSObject) performSelector:withObject:withObject:] + 24 
    16 UIKit        0x31eb1141 -[UIApplication sendAction:to:from:forEvent:] + 84 
    17 UIKit        0x31eb10e1 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 32 
    18 UIKit        0x31eb10b3 -[UIControl sendAction:to:forEvent:] + 38 
    19 UIKit        0x31eb0e05 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 356 
    20 UIKit        0x31eb1453 -[UIControl touchesEnded:withEvent:] + 342 
    21 UIKit        0x31eafddd -[UIWindow _sendTouchesForEvent:] + 368 
    22 UIKit        0x31eaf757 -[UIWindow sendEvent:] + 262 
    23 UIKit        0x31eaa9ff -[UIApplication sendEvent:] + 298 
    24 UIKit        0x31eaa337 _UIApplicationHandleEvent + 5110 
    25 GraphicsServices     0x31e4504b PurpleEventCallback + 666 
    26 CoreFoundation      0x3082cce3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26 
    27 CoreFoundation      0x3082cca7 __CFRunLoopDoSource1 + 166 
    28 CoreFoundation      0x3081f56d __CFRunLoopRun + 520 
    29 CoreFoundation      0x3081f277 CFRunLoopRunSpecific + 230 
    30 CoreFoundation      0x3081f17f CFRunLoopRunInMode + 58 
    31 GraphicsServices     0x31e445f3 GSEventRunModal + 114 
    32 GraphicsServices     0x31e4469f GSEventRun + 62 
    33 UIKit        0x31e51123 -[UIApplication _run] + 402 
    34 UIKit        0x31e4f12f UIApplicationMain + 670 
    35 SPARKvue       0x000031ff main + 70 
    36 SPARKvue       0x000031b4 start + 40 
) 
terminate called after throwing an instance of 'NSException' 
Program received signal: “SIGABRT”. 

Tutto ciò che sta accadendo per innescare questo è:

[[self measurementPointer] setMeasurementDescriptor:descriptor]; 

Detto questo,

[[meterDisplay measurementPointer] addObserver:self 
      forKeyPath:@"measurementDescriptor" 
      options:NSKeyValueObservingOptionNew 
      context:nil]; 

In sostanza, MeasurementPointer punto si oppone a MeasurementDescriptor oggetti - ed entrambi sono sottoclassi NSManagedObject. Gli oggetti MeasurementDescriptor descrivono una combinazione specifica "misurazione" e "unità" (ad es. "Temperatura (° C)" o "Velocità del vento (mph)"). MeasurementDescriptors sono qualcosa di simile ai singleton nella misura in cui ce n'è solo uno per ogni combinazione di unità di misura uniche.

MeasurementPointer sono referenziati da altri oggetti, sia oggetti modello che oggetti controller. Un MeasurementPointer fa riferimento a MeasurementDescriptor. Molti oggetti sono interessati a sapere quando un MeasurementPointer inizia a fare riferimento a un nuovo/diverso MeasurementDescriptor. Ad esempio, un tale cambiamento potrebbe comportare la modifica di un asse del display grafico. Oppure, nel codice sopra, il display del misuratore potrebbe mostrare un campione diverso (da una serie selezionata di campioni).

Penso che il problema fondamentale sia che un CGImage sta ricevendo un messaggio che non è destinato ad esso ... sfortunatamente, questo è intermittente, quindi non sono stato in grado di trovare un modello che lo inneschi.

+1

Questo è probabilmente a causa di un rilascio troppo da qualche altra parte.Il CGImage è stato assegnato nel punto in cui avrebbe dovuto essere un altro oggetto. –

+0

Questo era ciò di cui avevo paura ... la cosa strana è che è * sempre * un CGImage. O, almeno, oggi era CGImage 6 o 7 volte. Credo che accenderò NSZombieEnabled e controllarlo. Grazie. – westsider

risposta

36

Si dispone di un oggetto che ha dealloc'ed e non ha smesso di osservare un altro oggetto. Esegui tutte le chiamate -addObserver... e assicurati che corrispondano alle chiamate -removeObserver... almeno nello -dealloc e possibilmente nello -viewDidUnload in base alla struttura dell'applicazione.

+1

hai ragione. Non era un problema di dati di base. Avrei dovuto postare prima - ma risolvere questo problema ne ha scoperto un altro. Con NSZombieEnabled attivato, sono stato in grado di ottenere un avvertimento utile sugli oggetti deallocati inviati. – westsider

+0

Ho ottenuto un po 'di questo utilizzando un codice demo che non è stato scritto per annullare correttamente l'osservazione di qualcosa quando è andato via. Google mi ha portato qui. Ave il potente google. –

+0

La mia app utilizza ARC dove rimuovere l'osservatore? –

1

Ho avuto lo stesso problema, ma nel mio caso stavo osservando un contesto diverso. Poi ho messo tutto nello stesso contesto e lo schianto era sparito. Spero che questo aiuti qualcuno.

3

Mi sono imbattuto in questo problema passando accidentalmente il bersaglio in quanto l'osservatore (invece di sé) in questo modo:

[self.someView addObserver:self.someView forKeyPath:@"key" options:0 context:nil]; 

Il messaggio di errore non era affatto utile per identificare questo così appena ho pensato post nel caso in cui qualcun altro faccia la stessa cosa

6

Ho visto questo errore quando ho inviato il metodo observeValueForKeyPath a super, che non avevo registrato come osservatore per la modifica. Apple docs dire "Assicurati di chiamare l'implementazione della superclasse [di observeValueForKeyPath] se la implementa".

La mia difficoltà è stato quello di cambiare:

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    if ([keyPath isEqualToString:kPropertyThatChanges]) { 
    ... 
    } 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
} 

a:

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context { 
    if ([keyPath isEqualToString:kPropertyThatChanges]) { 
    ... 
    } 
} 
+0

Penso che questa risposta sia valida come la risposta accettata. – danh

+0

Non dovresti rimuovere la chiamata a 'super', rischiando KVO da altri keyPath per non funzionare se anche' super' sta osservando. Che cosa si dovrebbe fare è quello di mettere a chiamare 'super' a lato' else' '' ' if ([percorso chiave isEqualToString: kPropertyThatChanges]) { ... } else { [super observeValueForKeyPath: percorso chiave ofObject: oggetto cambiamento: cambia contesto: contesto]; } –

Problemi correlati