我有一个视图控制器订阅其他地方广播的通知。这是一个大对象图的一部分,它有一些需要在子元素被释放时进行的清理。但是dealloc从未在其中一个孩子中被调用(ARC环境),这个(如果我理解的话)意味着某个地方仍然被保留,从而导致ARC即使在VC被解雇时也永远不会被释放。我已经将违规代码追溯到以下两行。第一个版本导致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
,但这可行。
答案 0 :(得分: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/