Notifications causing no dealloc to be called

2019-07-10 05:31发布

问题:

I am trying to use this within a project: https://github.com/zakkhoyt/VWWPermissionKit

I do not understand KVO/Notification Center as much as I'd like so posting a question.

Basically the init and dealloc for the Permission Manager look like this:

- (instancetype)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserverForName:VWWPermissionNotificationsPromptAction object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
            dispatch_async(dispatch_get_main_queue(), ^{
                VWWPermission *permission = note.userInfo[VWWPermissionNotificationsPermissionKey];
                [permission presentSystemPromtWithCompletionBlock:^{
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [permission updatePermissionStatus];

                        if(permission.status == VWWPermissionStatusDenied){
                            [self.permissionsViewController displayDeniedAlertForPermission:permission];
                        }



                        [self checkAllPermissionsSatisfied];    
                    });
                }];
            });
        }];

        [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self readPermissions];
            });
        }];

    }
    return self;
}

-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

If I want to read a set of permissions I would call this:

NSArray *permissionsToRead = @[
                                [VWWCoreLocationWhenInUsePermission permissionWithLabelText:nil],
                                [VWWNotificationsPermission permissionWithLabelText:nil]
                                ];
[VWWPermissionsManager readPermissions:permissionsToRead resultsBlock:^(NSArray *permissions) {
// Do something with the result
    }
}];

This all works fine. The issue is that the dealloc is not being called, therefore the Notifications are still being called such as the UIApplicationDidBecomeActiveNotification being created in the init method.

As far as I can see the Permission Manager is created and not referenced and therefore it just hangs around.

The public method for the readPermssions is as follows:

+(void)readPermissions:(NSArray*)permissions resultsBlock:(VWWPermissionsManagerResultsBlock)resultsBlock{
    VWWPermissionsManager *permissionsManager = [[self alloc]init];
    [permissionsManager readPermissions:permissions resultsBlock:resultsBlock];
}

A new instance is created and another method is called then passes the resultsBlock back. There is nothing that releases this as far as I can tell. How would I get the dealloc to be called?

回答1:

It's because NSNotificationCenter is retaining the observer object, which is retaining the block that is registered with it, which is capturing your view controller and preventing it from being deallocated.

If you want your view controller to be able to be released then you should create a weak reference (__weak typeof(self) weakSelf = self;) to it outside the block and use weakSelf inside the block.

You also aren't removing the observer correctly. When you add an observer using the notification center block api it returns an object which is what it is actually adding as the observer and which you need to keep a reference to and pass to removeObserver:.

I would suggest just not using the method to observe with a block since it adds more management trouble than it's worth. Use the one that takes a selector instead.