Just a coder
Just a coder

Reputation: 16730

How do i get the information from the observationInfo method in Objective C KVO?

There is the observationInfo method which returns information of bindings of an object. I have looked around but i do not know how to get the information from the dictionary. Can any one lead me in the right direction please?

EDIT In case any one misunderstand that im saying. My classes are already all KVO compliant. Now after you add the observer to a something object, self.something will now have binding information. If i did [self.something observationInfo], this returns a dictionary. I would like to access the contents of that dictionary.

Apple docs said

For improved performance, this method and setObservationInfo: can be overridden to store the opaque data pointer in an instance variable. Overrides of this method must not attempt to send Objective-C messages to the stored data, including retain and release.

So i know that it can be done.. my question is how? I see no info any where on line.

Upvotes: 3

Views: 3856

Answers (4)

stone
stone

Reputation: 1

id aInstance = (__bridge id)self.observationInfo;
NSArray *list = [aInstance valueForKey:@"_observances"];
for (id object in list) {
    id observer = [object valueForKey:@"_observer"];
    //id property = [object valueForKey:@"_property"];
    //NSString *keyPath = [property valueForKey:@"_keyPath"];
    NSString *keyPath = [object valueForKeyPath:@"_property._keyPath"];
    [self.stone removeObserver:observer forKeyPath:keyPath];

    NSLog(@"%@ %@", observer, keyPath);
}

Upvotes: 0

John M
John M

Reputation: 1

This worked for me.

id anObserver = self;
NSString *observerString = [anObserver description];
NSString *str = [NSString stringWithFormat: @"%@", [aController observationInfo]];
NSRange rangeOfObserver = [str rangeOfString:observerString];
if (rangeOfObserver.location == NSNotFound) {
} else {
    [aController removeObserver:anObserver forKeyPath:@"selectionIndexes" context:NULL];
}

Upvotes: 0

ipmcc
ipmcc

Reputation: 29946

I suspect you're misunderstanding the purpose of -observationInfo/-setObservationInfo:. The value that is set and gotten by those methods is opaque to you. Put differently, its contents are private to the system frameworks and you're not intended to be able to access/parse it. The comment from the docs that you excerpted was:

For improved performance, this method and setObservationInfo: can be overridden to store the opaque data pointer in an instance variable. Overrides of this method must not attempt to send Objective-C messages to the stored data, including retain and release.

Let me try to clarify what this is saying a bit:

For every observation, the frameworks need to keep track of some private data about the observation in order to deliver it later. How it stores that information is not documented, but conceptually, it's probably stored in a map where the key is the pointer value of the object and the value is this opaque data structure.

In specific, performance-sensitive situations, it may be that looking up the observation info in that shared map impacts performance significantly (I've never seen this turn up on a profiling trace myself, but that's not to say it couldn't happen). In those cases, it would be better to store the pointer directly as an instance variable in the object, which changes the fetch operation from a map-lookup to a simple add. From a system frameworks perspective, I would bet that the map-lookup cost is usually far less onerous (in the big picture) than the alternative, which would be to put an instance variable in NSObject for this purpose (which would make every object 8 bytes bigger whether it uses KVO or not -- seems like a no-brainer.)

-observationInfo/-setObservationInfo: exist to allow you to make that optimization. If you implemented this optimization, these methods would also be a way to know if your object is being observed or not (i.e. is the info value nil?) which may allow you to make other changes to your object's behavior.

If you have a need to keep a list of observing objects and details about what they're observing for some other purpose, then you will need to do that yourself by overriding addObserver:... and removeObserver:..., and adding code to maintain your own data private structures (while still calling super.)

Upvotes: 8

Kyle Truscott
Kyle Truscott

Reputation: 1577

The object you're observing must be KVO compliant. This means that you can access the relevant information from the via normal dictionary syntax. For instance:

[self.something addObserver:self
                  forKeyPath:@"cheese"
                     options:NSKeyValueObservingOptionNew
                     context:NULL];

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

  if ([keyPath isEqualToString:@"cheese"])
  {
    // Get the new key value
    [object valueForKey:keyPath];

    // See the changes for the key value
    NSLog(@"Changes: %@", change);
  }
  else
  {
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  }
}

The KVO docs at Apple.

Upvotes: -1

Related Questions