Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 118 Vote(s) - 3.53 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How can I tell if an object has a key value observer attached

#11
FWIW, [`[someObject observationInfo]`](

[To see links please register here]

) 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.
Reply

#12
## Long Story Short
Take `NSObject` category from [here][1] and use it like this:
```lang-objc
if ([observable tdw_hasObserver:observer forKeyPath:@"key.path" context:nil error:nil]) {
[observable removeObserver:observer forKeyPath:@"key.path"];
} else {
// go on your merry way
}
```
___
### Public API approach
For many **Foundation** classes, which don't have any other observers but yours, you can just check `observationInfo` property value. The property returns a null pointer when the object doesn't have any observers or an opaque `void *` pointer otherwise:
```lang-objc
if (observable.observationInfo) {
[observable removeObserver:observer forKeyPath:@"key.path"];
} else {
// go on your merry way
}
```
This, however will not work for most of `UIKit` classes and scenarios where you yourself use more than one observer.

---
### Private API approach
If you don't mind messing with private API, any object can provide you with an opaque pointed to its observers data with use of [`NSObject`'s `observationInfo`][2] property. Under the hood the pointer holds an object which in turn holds an array of so-called **observances** - special data structure to describe a single *subscription* (every invocation of [`-[NSObject addObserver:forKeyPath:options:context:]`][3] creates a new instance in the array, even if *all* arguments are the same). An observance memory layout (at the time of writing this answer at least) looks something like this:
```lang-objc
@interface NSKeyValueObservance: NSObject {
id _observer;
NSKeyValueProperty *_property;
void *_context;
id originalObservable;
}
```
The combination of these variables is the information you are looking for. Of course you cannot reliably extract this data, because it's private API, however the following contract keeps working since ages ago:

1. `observationInfo` should have an `NSArray` ivar which holds observances data;
2. `_observer`, `_property` and `_context` ivars names are as is;
3. `_context` and `_observer` can be compared with the desired data by pointer addresses;
4. `_property` ivar has `_keyPath` of type `NSString` to compare with the desired key-path;

With that in mind you can extend `NSObject` with a category and implement a convenient method which checks whether certain combination is present or not.

I don't mind sharing my own implementation but it's a little too much to fit in a single SO answer. You can check it out in [my gists page][1].
Be advised, that this implementation performs ivars lookup by name and (sometimes) types. It is somewhat safer than just directly using ivar offsets, but still very fragile.

Here is a simple example of how to use it:
```lang-objc
NSObject *observable = [NSObject new];
NSObject *observer = [NSObject new];
void *observerContext = &observerContext;

[observable addObserver:observer forKeyPath:@"observationInfo" options:NSKeyValueObservingOptionNew context:observerContext];
[observable addObserver:observer forKeyPath:@"observationInfo" options:NSKeyValueObservingOptionNew context:nil];
[observable addObserver:observer forKeyPath:@"observationInfo" options:NSKeyValueObservingOptionNew context:observerContext];

// Removes only 2 observances (subscriptions) where all parts matches (context, keyPath and observer instance)
while ([observable tdw_hasObserver:observer forKeyPath:@"observationInfo" context:observerContext error:nil]) {
[observable removeObserver:observer forKeyPath:@"observationInfo" context:observerContext];
}
```
### Two-Sentence documentation
If `context` and/or `keyPath` arguments are `nil`, the implementation looks for subscriptions with **any** `context` and/or `keyPath`.

In case of any (expected) error, the method returns `NO` and writes error details to the `error` object, if corresponding pointer is provided. Expected errors include some minor changes in the private API (but far from any).


[1]:
[2]:

[To see links please register here]

[3]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through