2010-11-08 2 views
24

Я относительно новичок в KVO, поэтому есть хороший шанс, что я нарушаю какое-то фундаментальное правило. Я использую Core Data.An -observeValueForKeyPath: ofObject: change: context: сообщение получено, но не обработано

Мое приложение выходит из строя со следующим сообщением: И то, что я не могу понять, является причиной того, что CGImage участвует в наблюдении за значением, установленным на объекте 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”. 

Все, что происходит, чтобы вызвать это:

[[self measurementPointer] setMeasurementDescriptor:descriptor]; 

Учитывая это,

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

В основном, MeasurementPointer объекты указывают на MeasurementDescriptor объекты - и оба NSManagedObject подклассы. Объекты MeasurementDescriptor описывают конкретную комбинацию «измерение» и «единица» (например, «Температура (° C)» или «Скорость ветра (миль/ч)»). MeasurementDescriptors - это что-то вроде синглтонов в той мере, в которой есть только один для каждой уникальной комбинации единиц измерения.

Объекты MeasurementPointers ссылаются на другие объекты - объекты модели и объекты контроллера. A MeasurementPointer ссылается на MeasurementDescriptor. Многим объектам интересно знать, когда MeasurementPointer начинает ссылаться на новый/другой MeasurementDescriptor. Например, такое изменение может привести к изменению оси отображения графика. Или, в приведенном выше коде, может отображаться на дисплее счетчика другой образец (из выбранного набора образцов).

Я думаю, что основная проблема заключается в том, что CGImage получает сообщение, которое не предназначено для него ... к сожалению, это прерывисто, поэтому я не смог найти шаблон, который его запускает.

+1

Это, вероятно, из-за чрезмерный выпуск где-то еще.CGImage был выделен в месте, где должен был быть какой-то другой объект. –

+0

Это было то, чего я боялся ... странно, что это всегда * CGImage. Или, по крайней мере, сегодня это CGImage 6 или 7 раз. Думаю, я включу NSZombieEnabled и проверю это. Благодарю. – westsider

ответ

36

У вас есть объект, который получил dealloc'ed и не прекратил наблюдать за другим объектом. Пройдите все ваши звонки -addObserver... и убедитесь, что они совпадают с -removeObserver... вызовами по крайней мере в -dealloc и, возможно, в -viewDidUnload в зависимости от структуры приложения.

+1

Вы правы. Это не проблема с основными данными. Я должен был написать раньше, но исправление этой проблемы выявило еще одну проблему. Когда NSZombieEnabled включен, я смог получить полезное предупреждение о отправляемых сообщениях освобожденного объекта. – westsider

+0

Я немного поучаствовал в этом, используя какой-то демо-код, который не был написан, чтобы правильно не заметить что-то, когда оно ушло. Google привел меня прямо здесь. Приветствую могущественного Google. –

+0

Мое приложение использует ARC, где можно удалить наблюдателя? –

1

У меня была та же проблема, но в моем случае я наблюдал другой контекст. Затем я положил все в том же контексте, и авария исчезла. Я надеюсь, что это помогает кому-то.

3

Я столкнулся с этой проблемой, случайно проходя мишень в качестве наблюдателя (вместо себя) так:

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

Сообщение об ошибке не было вообще полезно в определении этого так просто думал, что я в случае, если кто-то другой сделает то же самое.

6

Я видел эту ошибку, когда отправил метод observeValueForKeyPath в super, который я не зарегистрировал в качестве наблюдателя для изменения. Apple docs говорят: «Обязательно вызовите реализацию суперкласса [observeValueForKeyPath] , если он реализует его."

Моего исправления было изменить:

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

к:

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

Я думаю, что этот ответ так же важен, как и принятый ответ. – danh

+0

Вы не должны удалять вызов 'super', рискуя KVO от другого keyPath, чтобы не работать, если также соблюдает' super'. То, что вы должны сделать, это положить звонить в 'super' в стороне' else' '' ' если ([isEqualToString: Ключевой путь kPropertyThatChanges]) { ... } еще { [супер observeValueForKeyPath: ofObject: Ключевой путь объекта изменить: изменить контекст: контекст]; } –

Смежные вопросы