Recently, in the process of making a tablet, some very irregular code has been found. Accidentally fix the payment bug, see the other project code, the use of the notice place is not removed, I thought I this module payment flash is because he notice not removed because of the reason. And in the debug and look at the specific code of the time only to find that there is no relationship. In my mind, I had a problem with the flashback because I didn't remove the notice. So I was surprised, so I wrote a demo to study the next, at the same time, the correct posture of the use of nsnotificationcenter.
Nsnotificationcenter
For this needless to say, is a message notification mechanism, similar to broadcasting. The observer only needs to register something of interest with the message center, and when there is a place to send the message, the Notification Center is sent to the object that registered the message. This also acts as a decoupling between multiple objects. Apple has encapsulated this nsnotificationcenter for us so that we can easily register and remove notifications. However, some people pose a little bit of a problem, let's look at the right posture!
Remove the correct posture
As long as the registration of the nsnotificationcenter, there must be a remove, this is a consensus. But everyone in the use of the time found that in the Uiviewcontroller after Addobserver not removed, as if not hanging! I think a lot of people may have the same question as me, is it because of the use of arc? When your object is destroyed, it automatically resets to nil? Or how did Apple use the magic in implementing this class? Let's explore the next step.
First, after addobserver to Nsnotificationcenter, there is no reference count plus 1 for this object, so it simply saves the address. In order to verify this operation, let's do the test of the code.
A test class that is used to register notifications:
123456789101112131415161718192021 |
@implementation MRCObject
- (id)init
{
if
(self = [
super
init]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(test) name:@
"test"
object:nil];
}
return self;
}
- (void)test
{
NSLog(@
"================="
);
}
- (void)dealloc
{
[
super
dealloc];
}
@end
|
This class is simple, which is to register a notification to him at the time of initialization. However, the remove operation is not performed at the time of destruction. We create this object in VC, then destroy, and finally send this notification:
12345678 |
- (void)viewDidLoad { [ super viewDidLoad]; MRCObject *obj = [[MRCObject alloc] init]; [obj release]; [[NSNotificationCenter defaultCenter] postNotificationName:@ "test" object:nil]; } |
After entering this VC, we found hung up. and the printed information is:
1 |
2015-01-19 22:49:06.655 测试[1158:286268] *** -[MRCObject test]: message sent to deallocated instance 0x17000e5b0 |
We can see that the message was sent to the wild pointer object, so it hung up. From this point of view, the Apple implementation is almost like this, only save the address of the object, and did not be destroyed at the time of nil.
This proves that, after Addobserver, a remove operation is required.
Now we register the notice in the Uiviewcontroller, do not remove, see if will hang off.
1234 |
- (void)viewDidLoad { [ super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(test) name:@ "test" object:nil]; } |
First Use Navigationcontroller to enter this page, then pop out. Last click on the button event to send notifications:
1234 |
- (void)didButtonClicked:(id)sender { [[NSNotificationCenter defaultCenter] postNotificationName:@ "test" object:nil]; } |
No matter how you click this button, he just doesn't hang up! This, is not very depressed? We can look for it, there is no remove operation in your code, but Nsnotificationcenter has been removed, otherwise there will be a problem with the wild pointer above. It seems to look, but also can only show that Uiviewcontroller himself destroyed when the time to help us secretly removed.
So how do we prove it? Because we do not see the source code, so we do not know that there is no call. This time, we can start from this Notice center!!! How do you do it? All I have to do is prove that Uiviewcontroller has called the Remove method at the time of destruction, and it proves that our conjecture is right! This is the time when we need to use our powerful category for this feature. We add a category to Nsnotificationcenter, overriding his-(void) Removeobserver: (ID) Observer method:
1234 |
- (void)removeObserver:(id)observer { NSLog(@ "====%@ remove===" , [observer class]); } |
So in our VC import this category, and then pop out to see what happened!
1 |
2015-01-19 22:59:00.580 测试[1181:288728] ====TestViewController remove=== |
What do you think? It is not possible to prove that the uiviewcontroller of the system calls this method when it is destroyed. (It is not recommended that you cover the original method in the same way when you develop it, because the category method has a higher priority, it is possible to affect other places.) This is just for debugging purposes).
The above also reminds us, when you are not destroyed, do not directly call [[Nsnotificationcenter Defaultcenter] removeobserver:self]; This method, because you may have removed notification of system registration.
Correct posture of attention repeat Addobserver
In our development, we can often see this code:
1234567891011 |
- (void) viewwillappear :(BOOL) animated { [ Super viewwillappear:animated]; [[Nsnotificationcenter defaultcenter] addobserver:self selector: @selector (test) name:@ "test" Object:nil]; } - (void) Viewwilldisappear: (BOOL) animated { [ Super viewwilldisappear:animated]; [[Nsnotificationcenter defaultcenter] removeobserver:self name:@ "test" Object:nil]; } |
is to register the notification when the page appears, and remove the notification when the page disappears. You have to pay attention to this side, must be paired to appear, if you only in Viewwillappear addobserver not in Viewwilldisappear removeobserver so when the message occurs, your method will be called multiple times, This must be borne in mind.
Multiple thread notifications for correct posture
First look at Apple's official note:
Regular Notification Centers deliver notifications on the thread in which the notification was posted. Distributed notification centers deliver notifications on the main thread. At times, your may require notifications to be delivered on a particular thread that's determined by you instead of the No Tification Center. For example, if an object running in a background thread was listening for notifications from the user interface, such as a Window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they is delivered on the default thread and redirect them to the AP Propriate thread.
The meaning is simple, the accepted thread of the Nsnotificationcenter message is based on the thread that sent the message. That is synchronous, so sometimes the message you send may not be the main thread, and everyone knows that the operating UI must be in the main thread, otherwise it will not respond. So, when you get a message notification, be careful to select the thread you want to execute. Here's a sample code
12345678910111213141516171819202122 |
//接受消息通知的回调
- (void)test
{
if
([[NSThread currentThread] isMainThread]) {
NSLog(@
"main"
);
}
else
{
NSLog(@
"not main"
);
}
dispatch_async(dispatch_get_main_queue(), ^{
//do your UI
});
}
//发送消息的线程
- (void)sendNotification
{
dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(defaultQueue, ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@
"test"
object:nil];
});
}
|
Summarize
Notice that the usual use of knowledge points almost so much. Hope to be of help to everyone. Finally, the code must develop a good habit, the removal or removal.
Copy from Jamesyu
Nsnotificationcenter use posture correctly, Removeobject explore