2010-11-08 9 views
24

Ich bin relativ neu in der KVO, also besteht eine gute Chance, dass ich gegen eine Grundregel verstoße. Ich verwende Core Data.Ein -ObserveValueForKeyPath: ofObject: change: context: Nachricht wurde empfangen, aber nicht bearbeitet

Meine App stürzt mit der folgenden Meldung ab: Und was ich nicht verstehen kann ist, warum ein CGImage an der Beobachtung eines Wertes beteiligt ist, der auf einem MeasurementPointer-Objekt festgelegt ist.

 *** 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”. 

Alles geschieht dies auslösen soll:

[[self measurementPointer] setMeasurementDescriptor:descriptor]; 

dies angesichts

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

Grundsätzlich MeasurementPointer Punktobjekte Objekte MeasurementDescriptor - und beide sind NSManagedObject Subklassen. MeasurementDescriptor-Objekte beschreiben eine spezifische Kombination aus "Messung" und "Einheit" (z. B. "Temperatur (° C)" oder "Windgeschwindigkeit (mph)"). MeasurementDescriptors sind so etwas wie Singletons in dem Maße, dass es für jede einzelne Messeinheitskombination nur einen gibt.

MeasurementPointers werden von anderen Objekten referenziert, sowohl von Model-Objekten als auch von Controller-Objekten. Ein MeasurementPointer verweist auf einen MeasurementDescriptor. Viele Objekte möchten wissen, wann ein MeasurementPointer beginnt, auf einen neuen/anderen MeasurementDescriptor zu verweisen. Eine solche Änderung kann zum Beispiel dazu führen, dass sich die Achse einer Grafikanzeige ändert. Oder, im obigen Code, könnte eine Anzeige auf dem Messgerät dazu führen, dass ein anderes Sample angezeigt wird (aus einem ausgewählten Sample-Set).

Ich denke, dass das grundlegende Problem ist, dass ein CGImage eine Nachricht empfängt, die nicht für es bestimmt ist ... leider ist dies intermittierend, so dass ich nicht in der Lage gewesen bin, ein Muster zu finden, das es auslöst.

+1

Dies ist wahrscheinlich wegen einer über Veröffentlichung woanders.Das CGImage wurde an der Stelle zugewiesen, wo ein anderes Objekt hätte sein sollen. –

+0

Das war, wovor ich Angst hatte ... das seltsame ist, dass es * immer * ein CGImage ist. Zumindest war es heute CGImage 6 oder 7 Mal. Ich schätze, ich werde NSZombieEnabled einschalten und das überprüfen. Vielen Dank. – westsider

Antwort

36

Sie haben ein Objekt, das freigegeben wurde und nicht aufhört, ein anderes Objekt zu beobachten. Gehen Sie durch alle Ihre -addObserver... Anrufe und stellen Sie sicher, dass sie mit -removeObserver... Anrufe mindestens in der -dealloc und möglicherweise in der -viewDidUnload abhängig von Ihrer Anwendungsstruktur abgestimmt sind.

+1

Sie haben Recht. Es war kein Kerndatenproblem. Ich hätte früher schreiben sollen - aber dieses Problem zu beheben, hat ein anderes entdeckt. Bei aktivierter NSZombieEnabled-Funktion konnte ich eine hilfreiche Warnung zu freigegebenen Objekten erhalten, die Nachrichten gesendet haben. – westsider

+0

Ich bekam dadurch etwas, indem ich Demo-Code benutzte, der nicht geschrieben wurde, um etwas zu bemerken, wenn es wegging. Google hat mich hierher gebracht. Heil den mächtigen Google. –

+0

Meine App verwendet ARC, um den Beobachter zu entfernen? –

1

Ich hatte das gleiche Problem, aber in meinem Fall beobachtete ich einen anderen Kontext. Dann habe ich alles in den gleichen Zusammenhang gestellt und der Absturz war weg. Ich hoffe, das hilft jemandem.

3

ich in dieses Problem lief versehentlich das Ziel in als Beobachter vorbei (statt Selbst) wie folgt:

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

Die Fehlermeldung nicht hilfreich war nur bei der Identifizierung dieser so dachte, ich würde Post für den Fall, dass jemand anderes dasselbe tut.

6

Ich sah diesen Fehler, als ich die observeValueForKeyPath-Methode an super sendete, die ich nicht als Beobachter für die Änderung registriert hatte. Apple docs sagen Sie: "Achten Sie darauf, die Implementierung der Superklasse [von observeValueForKeyPath] aufzurufen, wenn es implementiert."

Mein fix war zu ändern:

- (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]; 
} 

zu:

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

Ich denke, diese Antwort ist genauso gültig wie die angenommene Antwort. – danh

+0

Sie sollten den Aufruf nicht auf "super" entfernen, damit KVO von anderen keyPath nicht funktioniert, wenn "super" ebenfalls beobachtet. Was sollten Sie tun, ist zu 'super' in Seite zu setzen rufen' else' '' ' if ([keyPath isEqualToString: kPropertyThatChanges]) { ... } else { [super observeValueForKeyPath: keyPath ofObject: Objekt ändern: Kontext ändern: Kontext]; } –