What's the use of context parameter in following method which is used to register for key value notifications. The documentations just denotes it as arbitrary set of data.
addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil
Can somebody shed some light what's the purpose behind it ...
Key-value observing is a Cocoa programming pattern you use to notify objects about changes to properties of other objects. It's useful for communicating changes between logically separated parts of your app—such as between models and views. You can only use key-value observing with classes that inherit from NSObject .
Using a mechanism called key-value coding (KVC), you can manipulate object properties indirectly. With KVC comes the ability to observe changes to a particular key value, which is known as key-value observing (KVO).
Key-Value Observing, KVO for short, is an important concept of the Cocoa API. It allows objects to be notified when the state of another object changes.
KVO and KVC or Key-Value Observing and Key-Value Coding are mechanisms originally built and provided by Objective-C that allows us to locate and interact with the underlying properties of a class that inherits NSObject at runtime.
I hope this explanation isn't too abstract to understand.
Suppose you create a class MyViewController
, which is a subclass of UIViewController
. You don't have the source code of UIViewController
.
Now you decide to make MyViewController
use KVO to observe changes to the center
property of self.view
. So you duly add yourself as an observer:
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.view addObserver:self forKeyPath:@"center" options:0 context:NULL]; } - (void)viewDidDisappear:(BOOL)animated { [self.view removeObserver:self forKeyPath:@"center"]; [super viewDidDisappear:animated]; }
The problem here is that you don't know if UIViewController
also registers itself as an observer of self.view
's center
. If it does, then you might have two problems:
UIViewController
's KVO registration.You need a way to register yourself as an observer that is distinguishable from UIViewController
's KVO registration. That's where the context
argument comes in. You need to pass a value for context
that you are absolutely sure UIViewController
is not using as the context
argument. When you unregister, you use the same context
again so that you only remove your registration, not UIViewController
's registration. And in your observeValueForKeyPath:ofObject:change:context:
method, you need to check the context
to see if the message is for you, or for your superclass.
One way to be sure you use a context
that nothing else uses is to create a static
variable in MyViewController.m
. Use it when you register and unregister, like this:
static int kCenterContext; - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.view addObserver:self forKeyPath:@"center" options:0 context:&kCenterContext]; } - (void)viewDidDisappear:(BOOL)animated { [self.view removeObserver:self forKeyPath:@"center" context:&kCenterContext]; [super viewDidDisappear:animated]; }
Then in your observeValueForKeyPath:...
method, check it like this:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == &kCenterContext) { // This message is for me. Handle it. [self viewCenterDidChange]; // Do not pass it on to super! } else { // This message is not for me; pass it on to super. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }
Now you're guaranteed not to interfere with your superclass's KVO, if it does any. And if somebody makes a subclass of MyViewController
that also uses KVO, it won't interfere with your KVO.
Note too that you can use a different context for each key path you observe. Then, when the system notifies you of a change, you can check the context instead of checking the key path. Testing for pointer equality is a little faster than checking for string equality. Example:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == &kCenterContext) { [self viewCenterDidChange]; // Do not pass it on to super! } else if (context == &kBackgroundColorContext) { [self viewBackgroundDidChange]; // Do not pass it on to super! } else if (context == &kAlphaContext) { [self viewAlphaDidChange]; // Do not pass it on to super! } else { // This message is not for me; pass it on to super. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With