Handle UILocalNotification in UIViewController usi

2019-07-23 07:22发布

问题:

I'm working with UILocalNotification and I would like to notify one of my controller that the notification has been received even if the app has been terminated.

In my appDelegate I implemented this function:

-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    if ([application applicationState] == UIApplicationStateInactive) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"localNotificationReceived" object:notification.userInfo];
    }
}

In my UIViewController I implemented the observer on the viewDidLoad method

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didlocalNotificationReceived:) name:@"localNotificationReceived" object:nil];   

}

It works perfectly when the app run in background. Since the viewDidLoad method has already been called and the Observer is waiting..

The issue is when I kill the app. Then the observer of my controller is gone and the didlocalNotificationReceived method is never called.

I think that it's because when I receive the localNotification and run the app again. The didReceiveLocalNotification: method is called before the viewDidLoad of my UIViewController. Then the observer is created after the PostNotificationName then the observer receives nothing.

I would like to know if there is some best practices or pattern to handle this kind of issue.

I know that the didFinishLaunchingWithOptions method is called before didlocalNotificationReceived so there is probably something to do there.

UPDATE :

I also discovered that when is app is terminated. Once you tap the notification, It opens the app, call the function didFinishLaunchingWithOptions but never call didReceiveLocalNotification. So I think that I'm gonna handle both cases differently.

回答1:

Ok I found the answer.

I actually, initialize manually my storyboard, and be cautious that I initialize my main view before posting the NSNotification

My didFinishLaunchingWithOptions: method in my appDelegate looks like that:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    UIViewController *vc =[storyboard instantiateInitialViewController]; //call the initWithCoder: method of my controller

    if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        UILocalNotification *localNotification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"localNotificationReceived" object:localNotification.userInfo];
    }

    self.window.rootViewController = vc;
    [self.window makeKeyAndVisible];

    return YES;
}

Then in my UIViewController I create the NSNotification observer in the initWithCoder: method instead of in viewDidLoad:

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didlocalNotificationReceived:) name:@"localNotificationReceived" object:nil];
    }
    return self;
}

- (void)didlocalNotificationReceived:(NSNotification *)notification
{
    //Execute whatever method when received local notification
}

And when the app is not killed I still use the didReceiveLocalNotification: method:

-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    if ([application applicationState] == UIApplicationStateInactive) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"localNotificationReceived" object:notification.userInfo];
    }
}

I'm not sure if it's the best practice. But it works well !

Hope it'll help :)