Zhang
Zhang

Reputation: 11607

NSNotification not received by sub level view controller

-- Edit, see update solution below --

I have an app here where I download some data in a background thread.

Everytime 5 items are downloaded, in my main view controller, I post a notification that 5 items have been downloaded.

In one of my other 4 view controllers which they themselves are root view controllers on a navigation stack, I drill into a details page. (A typical 5 tab bar interface)

This details page is another View Controller in which I have done a NSNotificationCenter defaultCenter addObserver to the viewDidLoad method.

The problem here is that when the notification gets posted, the root view controller of my details page receives the notification but the details page itself does not receive the notification.

Although my data is being downloaded in a background thread, I am calling performSelectorOnMainThread: with a dispatch method. In the dispatch method, it calls [[NSNotificationCenter defaultCenter] postNotificationNamed:object:];

So:

.... downloading batches of 5 items in a background thread ....

...

... downloaded calling [self performSelectorOnMainThread:@selector(foo) WithObject:nil WaitUntilDone:NO]; ...

...

// foo method
-(void)foo
{
    // theoretically, this notification should be delivered and received in the main thread since this foo() method is told to execute on the main thread above 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"notif_batchDownloaded" object:nil];
}

...

I am receiving notifications in my root view controllers but not my details page.

1) when the download process begins, I am already viewing the details page so no, I don't think the details page view controller is deallocated

2) details page view controller is obviously observing the notification on the main thread and as stated above, the notification is told to be posted on the main thread.

So the question is, could there be any other reasons that is preventing a sub level view controller from receiving a notification?

I don't think I have exceeded any notification observer limitation. I have even commented out other notification but it made no difference.

The notification gets sent every single time 5 items gets downloaded, so there is no way I am viewing the details page before the notification gets sent. Even if I somehow missed the first 5, I should at least be receiving the 2nd 5, 3rd 5, 4th 5 and so on.

Could it be that the root view controller receives the notification first, then failed to pass on the notification to its sub level view controllers?

I am out of ideas.

UPDATE - culprit found!

I have finally found out where it broke. What a PITA.

In my previous viewDidLoad method, I had it like so:

-(void)viewDidLoad
{
    ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) name:@"notif_batchDownloaded" object:@"notif_batchDownloaded"];
    ...
}

The problem here is the "object" parameter that I passed in. I am using the name of the notification as a parameter to the "object" field but this somehow causes my doSomething() method to never get executed.

I removed the object parameter and now it works.

New viewDidLoad() should be like this:

-(void)viewDidLoad
{
    ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) name:@"notif_batchDownloaded" object:nil];
    ...
}

I had originally thought I could use the "object" parameter like some sort of tagging to help my callback method identify which notification was sent in the case that I had multiple notification sent to the same callback method.

A quick read of the Apple Documentation reveals that the object parameter is used for identifying which object the observer which to observe the notification from. I.e. multiple objects can send the same notification, this object parameter field identifies which object it wishes to receive the notification from only.

E.g.

View Controller A and View Controller B both postNotificationName:@"notif_foo".

View Controller C add itself as an observer of notification "notif_foo" but it can optionally choose to receive "notif_foo" only from View Controller A by specifying view controller A as the object parameter.

Stupid me didn't realise in my notification callback method I can go:

if([notification name] isEqualToString:@"notifName"])
{
   ...
}
else
{
   ...
}

Hope this helps anyone else who is pulling their hairs out on this problem.

Upvotes: 1

Views: 1155

Answers (1)

Saad
Saad

Reputation: 8947

you can set flags in appdelegate that will tell which controller is selected. then post notification of that controller. note here you will need to implement your code in all the class where you want to post notification specially if there is ui changes or the class is released

Upvotes: 0

Related Questions