开发者

NSInternalInconsistencyException when using KVO

I'm trying to use a KVO example I got from an iPhone tutorial book, but get this exception

   Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<UINavigationController: 0x139630>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: dataUpdated
Observed object: <FilterDetailsController: 0x1b9930>
Change: {
    kind = 1;
}
    Context: 0x0'
     Call stack at first throw:
    (
        0   CoreFoundation                      0x320d3987 __exceptionPreprocess + 114
        1   libobjc.A.dylib                     0x3271849d objc_exception_throw + 24
        2   CoreFoundation                      0x320d37c9 +[NSException raise:format:arguments:] + 68
        3   CoreFoundation                      0x320d3803 +[NSException raise:format:] + 34
        4   Foundation                          0x35c316e9 -[NSObject(NSKeyValueObserving) observeValueForKeyPath:ofObject:change:context:] + 60
        5   Foundation                          0x35bd4a3d NSKeyValueNotifyObserver + 216
        6   Foundation                          0x35bd46e5 NSKeyValueDidChange + 236
        7   Foundation                          0x35bcc3f5 -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 76
        8   Foundation                          0x35c30d87 _NSSetObjectValueAndNotify + 98
        9   Lucid Dreaming App                  0x000108e3 -[FilterDetailsController adjustFilterDetails:] + 138
        10  CoreFoundation                      0x3207afed -[NSObject(NSObject) performSelector:withObject:withObject:] + 24
        11  UIKit                               0x323b3ea5 -[UIApplication sendAction:to:from:forEvent:] + 84
        12  UIKit                               0x323b3e45 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 32
        13  UIKit                               0x323b3e17 -[UIControl sendAction:to:forEvent:] + 38
        14  UIKit                               0x323b3b69 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 356
        15  UIKit                               0x323b43c7 -[UIControl touchesEnded:withEvent:] + 342
        16  UIKit                               0x323a9d4d -[UIWindow _sendTouchesForEvent:] + 368
        17  UIKit                               0x323a96c7 -[UIWindow sendEvent:] + 262
        18  UIKit                               0x3239499f -[UIApplication sendEvent:] + 298
        19  UIKit                               0x323942df _UIApplicationHandleEvent + 5090
        20  GraphicsServices                    0x35472f03 PurpleEventCallback + 666
        21  CoreFoundation                      0x320686ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26
        22  CoreFoundation                      0x320686c3 __CFRunLoopDoSource1 + 166
        23  CoreFoundation                      0x3205af7d __CFRunLoopRun + 520
        24  CoreFoundation                      0x3205ac87 CFRunLoopRunSpecific + 230
        25  CoreFoundation                      0x3205ab8f CFRunLoopRunInMode + 58
        26  GraphicsServices                    0x354724ab GSEventRunModal + 114
        27  GraphicsServices                    0x35472557 GSEventRun + 62
        28  UIKit                               0x323c7d21 -[UIApplication _run] + 412
        29  UIKit  ...

I start by

[advancedController addObserver:self.navigationController forKeyPath:@"dataUpdated" options:0 context:nil];

within self.navigation controller, I have the observation method defined:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{

    NSLog(@"2 Observed change for: %@",keyPath);
//    if (context == <#context#>) {
//        <#code to be executed upon observing keypath#>
//    } else {
        [super observeValueForKeyP开发者_如何学运维ath:keyPath ofObject:object change:change context:context];
//    }
}

within advancedController I have a NSNumber property

 @property(nonatomic,retain)NSNumber* dataUpdated;

When I hit a button, I expect the observer to fire.

  - (IBAction)adjustFilterDetails:(id)sender {
        self.dataUpdated = [NSNumber numberWithInt:[self.dataUpdated intValue]+1];
    }

Do I need to implement some protocol or explicitly state that I will update the value? I read that NSKeyValueObserving is an "informal" protocol. Thank you for your help!

I have figured out the answer to my own question. I had the KVO protocol method defined within a ViewController, however, I have accidentally registered the Navigation controller for the View controller to observe the value. The correct object is found by getting the view controller like this:

 [advancedController addObserver:(RootViewController*)self.navigationController. topViewController forKeyPath:@"dataUpdated" options:0 context:nil];


Your problem is the call to super. You shouldn't pass this method to super for properties that you observed yourself. You commented out the code that was there to help you with this.

A possible correct observation would be (note the context):

[advancedController addObserver:self.navigationController forKeyPath:@"dataUpdated" options:0 context:self];

And then the correct observer would be:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{
    if (context == self) {
        NSLog(@"2 Observed change for: %@",keyPath);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Dave Dribin provides another approach to using context correctly, along with the backstory of why it's necessary, in Proper Key-Value Observer Usage.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜