Whether to use NSNotification or KVO

There can be a few conflicting techniques to solve a problem. Any can be chosen to achieve your goal.

However, sometimes I want to know what can fit better for this and that.

One of those conflicting techniques are KVO and Notification in a same process or a task.

KVO is to have one object to monitor other object to see if there are any changes.

Notification is to send an alarm to a monitoring object if something happens. For both, an monitoring object should be registered to some entities. So, mostly they are very similar.

Then which one to use?

It depends on your preference, requirement by a target object, or what granularity you want. Also, system bottleneck can be considered.

First, let’s consider system or requirement-wise decision.

Notification requires a notification center, i.e. NSNotificationCenter. This is a system-wide place. So, things from other processes are to be enqueued and it should manage them. This means the delivery on time is not guaranteed. While KVO is direct communication between objects. So, things can be faster.

However, for many Cocoa objects there are already pre-defined notification. Also for some classes, if a delegation object is set, without registering for notification, the delegation object can catch the notification. This is very handy. In that case notification is preferred.

ADDED : According to NSNotifications and their Rationale section of Notification Programming Topics, it is a process-specific and default is synchronous. I don’t know why I thought it the other way. Thank you, John for pointing out this!

Second, what to choose when you are to implement two objects, one of them needs to monitor the other?

You can either implement notification or KVO. This will be the most curious part.

If you use KVO, the monitoring object, i.e. observing object, should know the key path of the observed object. The key path mean the member variable names of an observed object. Let’s take a look at this example.

@interface JAObserved : NSObject {

	NSString *name;
	int price;
}

@property (retain) NSString *name;
@property int price;

@end

[List 1] Observed Object

@implementation JAObserver

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

	KVO_testAppDelegate *appDelegate = [NSApp delegate];

	//NSAssert( [change valueForKey:NSKeyValueChangeKindKey] == NSKeyValueChangeSetting, @"It is not change-related." );

	NSString *msgString;

	if( [keyPath isEqualToString:@"price"] )
	{
		msgString = [NSString stringWithFormat:@"Price is changed from %d to %d.\n",
							   [[change objectForKey:NSKeyValueChangeOldKey] intValue],
							   [[change objectForKey:NSKeyValueChangeNewKey] intValue]];
	}
	else if( [keyPath isEqualToString:@"name"] )
	{
		msgString = [NSString stringWithFormat:@"name is changed from %@ to %@\n",
					 [change objectForKey:NSKeyValueChangeOldKey],
					 [change objectForKey:NSKeyValueChangeNewKey]];
	}
	else if( [keyPath isEqualToString:@"observedTextField"] )
	{
		msgString = [NSString stringWithFormat:@"text field is changed from %@ to %@\n",
					 [change objectForKey:NSKeyValueChangeOldKey],
					 [change objectForKey:NSKeyValueChangeNewKey]];
	}
	else
	{
		msgString = [NSString stringWithString:@"Something else...\n"];
	}

	[[appDelegate.messageView documentView] insertText:msgString];

}

// Notification
- (void)controlTextDidChange:(NSNotification *)aNotification
{

	KVO_testAppDelegate *appDelegate = [NSApp delegate];

	NSString *newText = [[[aNotification userInfo] objectForKey:@"NSFieldEditor"] string];;
	NSString *msgString = [NSString stringWithFormat:@"New Text : %@\n", newText];

	[[appDelegate.messageView documentView] insertText:msgString];

}

@end

[Listing 2] Observer’s codes

Sometimes, though, it would not be easy to get the key paths for member variables of observed objects. Then using notification is easier because it will convey all information on what is changed from what value to what value. It means you don’t need to look further in your source codes. Just debug your interested part and examine a notification object to figure those information out.

Also, notification can provide more granularity for doing some extra chores before and after the observed property is actually changed.

[[NSNotificationCenter defaultCenter]
    postNotificationName:@"kBalanceWillChange" object:self];

 openingBalance = theBalance;

[[NSNotificationCenter defaultCenter]
    postNotificationName:@"kBalanceDidChange" object:self];

[List 3] Posting a notification

[List 3] shows how a notification message is posted. So, before you change some value of a given object, you can post “willChange” notification, and post “didChange” after changing it.

Then separated notification handlers for them will be called and things can be examined and you can do extra jobs there before and after the value is changed.

KVO, on the other hands, looks like this.

- (void)setOpeningBalance:(double)theBalance {

    if (theBalance != openingBalance) {

        [self willChangeValueForKey:@"openingBalance"];

        openingBalance=theBalance;

        [self didChangeValueForKey:@"openingBalance"];
    }
}

For KVO, you should call “willChangeValueForKey” and “didChangeValueForKey”. But they don’t generate separated event just like notification case.

So, I think notification is more flexible, but it depends. Although Notification makes things easy when there are multiple object monitoring to one object and you need monitoring mechanism within different sub-system, KVO can provide more sure response because it doesn’t require a central entity, notification center. So, if you write a program which sends lots of notification messages, the chance not to receive the messages on time can become higher. Then, you will be able to replace many of them with KVO and get benefit from it.

For more information, here is Apple’s document about when Notification and KVO can be good.

About these ads

7 responses to this post.

  1. NSNotificationCenter is actually specific to an application. The notifications are delivered synchronously so that the next line of code after posting will not get called until all observers have run their code. For this reason it can be useful to launch a thread when receiving the notification for more involved processing. If you want to do this asynchronously you would need to use NSNotificationQueue. To use notifications across the system you would need to use NSDistributedNotificationCenter (subclass of NSNotificationCenter).

    Reply

    • Posted by jongampark on February 18, 2011 at 7:15 PM

      Hmm.. right.. Why did I think that it was system wide? BTW, what do you think about this topic? When you do think it is better to use KVO and notification?

      Reply

    • Posted by jongampark on February 18, 2011 at 7:16 PM

      BTW, I used distributed object, NSDistributedNotificationCenter and NSNotification in different projects. This post is to summarize rationale for different mechanism especially KVO and notification system.

      Reply

      • I see the arguments for NSDistributedNotificationCenter as a completely different topic as NSNotificationCenter even if it is a subclass. The only reason you would use the distributed subclass is to go cross process. I’ve never actually needed to use it. I have taken advantage of NSNotificationQueue though which is quite nice for coalescing notifications. It would be nice if there was some good delineation between NSNotification and KVO but ultimately they are both tools. You can turn a phillips screw with a normal screwdriver but it would be easier with a phillips screwdriver. It all boils down to picking the right tool for the job which is often times a subjective judgement. As much as I wish there was a correct answer I think it’s something which will often garner opinions from both camps.

        Reply

  2. Posted by jianhua on December 29, 2011 at 5:11 AM

    Compared with NSNotification, KVO is much lighter.

    Reply

    • Posted by jongampark on December 29, 2011 at 8:13 AM

      Any thought on why KVO or NSNotification is better than the other by design or its nature?
      We know that KVO is much lighter because it is between the observed entity and the observing entity.

      Thank you.

      Reply

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 43 other followers

%d bloggers like this: