1

我有一个订阅其他地方广播的通知的视图控制器。这是一个大型对象图的一部分,当孩子被释放时,需要进行一些清理。但是在其中一个孩子(ARC环境)中从未调用过dealloc,这(如果我理解的话)意味着某处仍然保留了某些东西,因此即使VC被解雇,ARC也永远不会dealloc。我已经将有问题的代码追溯到以下两行。第一个版本导致 VC 和孩子永远不会被完全释放。在第二个版本中,一切正常,当这个 VC 被解散时,一切都得到了释放。

我的问题是为什么?使用 ARC,我无法理解为什么这个额外的 NSArray 不能正确发布。

希望这是足够的代码。有需要可以多发。

这是导致 VC(和孩子等)永远不会被完全释放的版本:

// Subscribe to notifications that the number of trackables has changed
[[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        NSArray *activeTrackableNames = note.object; // <-- offending line
        [self trackableUpdate:activeTrackableNames]; // <-- offending line
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

但是当我按照以下方式执行此操作时,当视图被卸载时,一切都会正确释放,因此在子 VC 上调用了 dealloc:

// Subscribe to notifications that the number of trackables has changed
[[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        [self trackableUpdate:note.object]; // <-- seems to work
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

此 VC 中可能(?)发挥作用的其他一些相关方法:

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    self.trackablesVisible_private = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Target Handling
-(void)trackableUpdate:(NSArray *)trackablesArray {
    NSLog(@"Trackable Changed");
    if (([trackablesArray count] > 0) && [self.delegate respondsToSelector:@selector(foundValidTargets:)]) {
        [delegate foundValidTargets:trackablesArray];
    }
    self.trackablesVisible_private = trackablesArray;
}

我不明白这里发生了什么。有人可以启发我吗?

谢谢!

编辑:

因此,正如回复中所述,部分问题是由于未能self在块中使用弱项而导致的保留周期,但显然这里还有另一个问题,因为我正在使用通知中心。解决方案在这里描述:Dealloc Not Running When Dismissing Modal View from Block

我的最终工作代码如下:

@interface

__weak id observer;

loadView

__weak ThisViewController *blockSelf = self; // Avoids retain cycle
observer = [[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        ThisViewController *strongSelf = blockSelf; // Avoids retain cycle
        NSArray *activeTrackableNames = note.object;
        [strongSelf trackableUpdate:activeTrackableNames];
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

而在viewWillDisappear

[[NSNotificationCenter defaultCenter] removeObserver:observer];

我还不完全明白为什么你必须保存返回的观察者对象,而不是仅仅删除self,但这有效。

4

1 回答 1

2

你的块中有一个保留周期......这就是你想要的

__weak MyViewControllerName *bSelf = self;
// Subscribe to notifications that the number of trackables has changed
[[NSNotificationCenter defaultCenter] addObserverForName:kUpdatedNumberofTrackables object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    if ([note.object isKindOfClass:[NSArray class]]) {
        **NSArray *activeTrackableNames = note.object;
        [bSelf trackableUpdate:activeTrackableNames];**
    } else {
        NSLog(@"Observer error. Object is not NSArray");
    }
}];

有关块和保留周期的更多信息,请查看http://zearfoss.wordpress.com/2012/05/11/a-quick-gotcha-about-blocks/

于 2013-04-19T22:11:12.813 回答