Search code examples
iosuipickerviewnsnotificationsnsnotificationcenteruipicker

Problems with NSNotificationCenter and UIPickerView


I hope I have better luck with someone helping me on this one:

I have a UIPickerView where a user makes a selection and then presses a button. I can gladly obtain the users choice, as shown in my NSLog, and when this is done, I want to send a notification to another view controller that will show a label with the option selected. Well, although it seems everything is done right, somehow it does not work and the label stays intact. Here is the code:

Broadcaster:

 if ([song isEqualToString:@"Something"] && [style isEqualToString:@"Other thing"])

{
    NSLog (@"%@, %@", one, two);
    [[NSNotificationCenter defaultCenter] postNotificationName:@"Test1" object:nil];

ReceiverViewController *receiver = [self.storyboard instantiateViewControllerWithIdentifier:@"Receiver"];
    [self presentModalViewController:receiver animated:YES];

}

Observer:

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
{
    [[NSNotificationCenter defaultCenter] addObserver:self     selector:@selector(receiveNotification) name:@"Test1" object:nil];
}
    return self;
}

-(void)receiveNotification:(NSNotification*)notification
{

if ([[notification name] isEqualToString:@"Test1"]) 
{

    [label setText:@"Success!"];
    NSLog (@"Successfully received the test notification!");
}

else

{
    label.text = @"Whatever...";
}


}

Solution

  • The issue is likely that the notification is sent (and therefore received) on a different thread than the main thread. Only on the main thread will you be able to update UI elements (like a label).

    See my answer to this question for some insight into threads and NSNotifications.

    Use something like:

    NSLog(@"Code executing in Thread %@",[NSThread currentThread] );
    

    to compare your main thread versus where your recieveNotifcation: method is being executed.

    If it is the case that you are sending the notification out on a thread that is not the main thread, a solution may be to broadcast your nsnotifications out on the main thread like so:

    //Call this to post a notification and are on a background thread      
    - (void) postmyNotification{
      [self performSelectorOnMainThread:@selector(helperMethod:) withObject:Nil waitUntilDone:NO];
    }
    
    //Do not call this directly if you are running on a background thread.
    - (void) helperMethod{
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SOMENAME" object:self];
    }
    

    If you only care about the label being updated on the main thread, you can perform that operation on the main thread using something similar to:

    dispatch_sync(dispatch_get_main_queue(), ^(void){
                                [label setText:@"Success!"];
                            });
    

    Hope that was helpful!