iOS NSNotificationCenter Observer not being remove

2019-05-14 03:09发布

问题:

I have the following code within AppDelegate. The purpose being to create a couple of observers, and then call some code. Once that code completes it then posts a notification, and the observer should then remove both observers and call the completion handler.

My issue is that it appears that the observers are not being removed as I expected. The notification is posted, and the NSLog entry is written to console, so I know that the observer is working. However, on the second time of calling, the NSLog is called twice, third time three times etc.

My thoughts are that this is to do with the removal being within the block of code that is running from the observer, however, I am unsure how I can resolve this (if indeed this is what the issue is).

Could someone be so kind as to explain how I can achieve this?

Thanks.

-(void) application:(UIApplication *)application performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {

    [[NSNotificationCenter defaultCenter] addObserverForName:@"fetchDidCompleteNewData" object:nil
                                                     queue:nil usingBlock:^(NSNotification *completed) {

                                                         //Remove Observers
                                                         [[NSNotificationCenter defaultCenter] removeObserver:self
                                                                                                         name:@"fetchDidCompleteNewData"
                                                                                                       object:nil];
                                                         [[NSNotificationCenter defaultCenter] removeObserver:self
                                                                                                         name:@"fetchDidCompleteNoData"
                                                                                                       object:nil];


                                                         // Post completion
                                                         completionHandler(UIBackgroundFetchResultNewData);
                                                         NSLog(@"Background fetch completed... New Data");
                                                     }];

    [[NSNotificationCenter defaultCenter] addObserverForName:@"fetchDidCompleteNoData" object:nil
                                                       queue:nil usingBlock:^(NSNotification *completed) {

                                                           //Remove Observers
                                                           [[NSNotificationCenter defaultCenter] removeObserver:self
                                                                                                           name:@"fetchDidCompleteNoData"
                                                                                                         object:nil];

                                                           [[NSNotificationCenter defaultCenter] removeObserver:self
                                                                                                           name:@"fetchDidCompleteNewData"
                                                                                                         object:nil];

                                                           //post completion
                                                           completionHandler(UIBackgroundFetchResultNoData);
                                                           NSLog(@"Background fetch completed... No New Data");

                                                       }];

    GetDetails *getDetails = [[GetDetails alloc] init];
    [getDetails backgroundRefresh];

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

    return YES;
}

回答1:

You are not registering self as an object. Moreover, when the block is pushed onto the stack by addObserverForName: the method has not yet returned so the notification is nil.

Make a global object using block, eg

__block __weak id notification;

then,

notification =  [[NSNotificationCenter defaultCenter] addObserverForName:@"fetchDidCompleteNewData" object:nil queue:nil usingBlock:^(NSNotification *completed) {

   //Remove Observers
   [[NSNotificationCenter defaultCenter] removeObserver:notification];
}];


回答2:

My thoughts are that this is to do with the removal being within the block of code that is running from the observer, however, I am unsure how I can resolve this (if indeed this is what the issue is).

Could someone be so kind as to explain how I can achieve this?

Certainly.

You can easily test your theory by not using the addObserverForName:object:queue:usingBlock: method and instead using the addObserver:selector:name:object: method, where the selector is the name of a function you call instead of using a block.

Simply use the API guide for NSNotificationCenter for details about these methods, or in general, since you question was about what other method you could use that does not require a block statement, consulting the API is the first place to check for alternative tools within the class.