How can i tell if an object has a key value observer attached

前端 未结 10 1492
萌比男神i
萌比男神i 2020-12-04 06:51

if you tell an objective c object to removeObservers: for a key path and that key path has not been registered, it cracks the sads. like -

\'Cannot remove an observe

相关标签:
10条回答
  • 2020-12-04 07:05

    Put a try catch around your removeObserver call

    @try{
       [someObject removeObserver:someObserver forKeyPath:somePath];
    }@catch(id anException){
       //do nothing, obviously it wasn't attached because an exception was thrown
    }
    
    0 讨论(0)
  • 2020-12-04 07:07

    In my opinion - this works similar to retainCount mechanism. You can't be sure that at the current moment you have your observer. Even if you check: self.observationInfo - you can't know for sure that you will have/won't have observers in future.

    Like retainCount. Maybe the observationInfo method is not exactly that kind of useless, but I only use it in debug purposes.

    So as a result - you just have to do it like in memory management. If you added an observer - just remove it when you don't need it. Like using viewWillAppear/viewWillDisappear etc. methods. E.g:

    -(void) viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        [self addObserver:nil forKeyPath:@"" options:NSKeyValueObservingOptionNew context:nil];
    }
    
    -(void) viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        [self removeObserver:nil forKeyPath:@""];
    }
    

    And it you need some specific checks - implement your own class that handles an array of observers and use it for your checks.

    0 讨论(0)
  • 2020-12-04 07:08

    When you add an observer to an object you could add it to a NSMutableArray like this:

    - (void)addObservedObject:(id)object {
        if (![_observedObjects containsObject:object]) {
            [_observedObjects addObject:object];
        }
    }
    

    If you want to unobserve the objects you can do something like:

    for (id object in _observedObjects) {
        if ([object isKindOfClass:[MyClass class]]) {
            MyClass *myObject = (MyClass *)object;
            [self unobserveMethod:myObject];
        }
    }
    [_observedObjects removeAllObjects];
    

    Remember, if you unobserve a single object remove it from the _observedObjects array:

    - (void)removeObservedObject:(id)object {
        if ([_observedObjects containsObject:object]) {
            [_observedObjects removeObject:object];
        }
    }
    
    0 讨论(0)
  • 2020-12-04 07:13

    In addition to Adam's answer I would like to suggest to use macro like this

    #define SafeRemoveObserver(sender, observer, keyPath) \
    @try{\
       [sender removeObserver:observer forKeyPath:keyPath];\
    }@catch(id anException){\
    }
    

    example of usage

    - (void)dealloc {
        SafeRemoveObserver(someObject, self, somePath);
    }
    
    0 讨论(0)
  • 2020-12-04 07:23

    FWIW, [someObject observationInfo] seems to be nil if someObject doesn't have any observers. I wouldn't trust this behavior, however, as I haven't seen it documented. Also, I don't know how to read observationInfo to get specific observers.

    0 讨论(0)
  • 2020-12-04 07:23

    I am not a fan of that try catch solution so what i do most of the time is that i create a subscribe and unsubscribe method for a specific notification inside that class. For example these two methods subcribe or unsubscribe the object to the global keyboard notification:

    @interface ObjectA : NSObject
    -(void)subscribeToKeyboardNotifications;
    -(void)unsubscribeToKeyboardNotifications;
    @end
    

    Inside those methods i use a private property which is set to true or false depending on the subscription state like so:

    @interface ObjectA()
    @property (nonatomic,assign) BOOL subscribedToKeyboardNotification
    @end
    
    @implementation
    
    -(void)subscribeToKeyboardNotifications {
        if (!self.subscribedToKeyboardNotification) {
            [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardShow:) name:UIKeyboardWillShowNotification object:nil];
            [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardHide:) name:UIKeyboardWillHideNotification object:nil];
            self.subscribedToKeyboardNotification = YES;
        }
    }
    
    -(void)unsubscribeToKeyboardNotifications {
        if (self.subscribedToKeyboardNotification) {
            [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillShowNotification object:nil];
            [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
            self.subscribedToKeyboardNotification = NO;
        }
    }
    @end
    
    0 讨论(0)
提交回复
热议问题