"message was received but not handled" KVO
Asked Answered
D

4

25

I'm getting the following in my output window when running a project:

An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: connection.messageQueue
Observed object: <Client: 0x10011ddb0>
...

You get the idea. The thing is, I have no idea why this is happening. It appears everything is working fine, however. Here's the code causing the problem:

-(id) initWithIdentifier:(NSString*)ident andClient:(Client*)chatClient {
    if(![super initWithNibName:@"ChatView" bundle:nil]) {
        return nil;
    }
    [self setTitle: ident];
    client = chatClient;
    [self setIdentifier:ident];

    inContext = false;

    [client addObserver:self forKeyPath:@"connection.messageQueue" options:NSKeyValueObservingOptionNew context:NULL];
    return self;
}

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSAttributedString* rar = [[NSAttributedString alloc] initWithString:@"test"];
    [[textView textStorage] appendAttributedString:rar];
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

I thought I'd show all the code relating to this. The class only has a few methods so this is all you need to see. I'm not even using the change, I'm just plucking on "test" when the KVO event gets fired.

The stack trace gets pretty big very quickly as messages are coming in all the time. Yet it seems everything is working okay.

Any clues?

Domeniga answered 4/9, 2012 at 19:52 Comment(0)
W
52

You should not call [super observeValueForKeyPath:ofObject:change:context:] if you handle the notification. You should only call this for notifications you do not yourself handle.

Whittaker answered 4/9, 2012 at 19:55 Comment(3)
Indeed, I am aware. It was some test code from earlier. The problem exists regardless of that, however.Domeniga
The message typically indicates that you have accidentally called the NSObject implementation, either by calling super or by failing to implement the observation method. That suggests that some other object is observing connection.messageQueue without implementing this method, or that you have mistyped the method name (it is long). The stack trace shouldn't get large just because of many messages coming in.Whittaker
If the stack trace is excessively large, make sure you don't have an infinite loop (perhaps an observer modifying the property it observes). You would expect problems then, though you might not notice them on a background thread.Whittaker
F
17

I have got the same problem: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. I have googled here, then I figured it out by myself, so maybe it helps someone.

For me, the problem was: the object registered as the observer (if you have ... addObserver:self ... then that object is self) has been released at the moment when the value was changed. But the observer was still registered, so -observeValueForKeyPath:ofObject:change:context: message was received by the nil observer.

Frightfully answered 17/1, 2013 at 8:1 Comment(3)
Remove the observer before the object is released.Frightfully
Like a huge genius I managed to get the same problem, with essentially the same cause, by mentally switching into key-path mode and registering @"self" (yes, the constant string) rather than self (the object that wanted to observe). Obviously the string doesn't handle key-value observing notifications. Also my psyche may not handle the self esteem blow from such a stupid error.Ruysdael
Same problem, but the solution lay in letting Code Completion redo '- (void)observeValueForKeyPath:' etc. No idea what went wrong -- it compiled -- but something went astray in the method name and it was never called, resulting in the message was received but not handled error.Alexandrine
B
8

It's easy to accidentally use code completion to override class func observeValue... rather than override func observeValue..., which was the problem in my case. In other words, make sure you are implementing the correct override.

Bea answered 5/10, 2022 at 16:22 Comment(1)
Big brain moment! This one helped for realzies!Cudlip
S
1

Make sure you only call super on the stuff you're not interested in.

class Layer: CALayer {
    
    private let key1 = "transport"
    private let key2 = "position"
        
    override init() {
        super.init()
        addObserver(self, forKeyPath: key1, options: [], context: nil)
        addObserver(self, forKeyPath: key2, options: [], context: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == key1 || keyPath == key2 {
            
        } else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
    
    deinit {
        removeObserver(self, forKeyPath: key1)
        removeObserver(self, forKeyPath: key2)
    }
}
Soledadsolely answered 3/6, 2021 at 7:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.