[编辑:由于它引起了混乱,整个案例假设 MRR 而不是 ARC]
我有一个奇怪的行为(显然有一个解释,我只是想不通)一个块引用自我(间接)并被复制到另一个对象的属性(即,从对象 As' 堆栈复制到堆并由对象 B) 保留。如果该块不包含对 _this 的引用,则每次从导航控制器弹出对象 A 的 dealloc 时都会调用它,这是应该的。但是,如果块引用 _this,则对象的(下面代码中的 MyObjectA)dealloc 只会每隔一次调用一次。也就是说,我推送这个视图控制器子类,调用 createBlock,然后弹出并没有任何反应。我再次推送,再次调用 createBlock,然后弹出,然后它确实在 MyObjectA 上调用 dealloc。
为简洁起见,我只发布我认为是行为关键的片段。
假设我有一个对象 MyObjectA(自定义 UIViewController 的子类),其中包括一个方法 createBlock,如下所示:
- (void)createBlock
{
__block MyObjectA* _this = self;
int(^animationBlock)(NSArray*,NSDictionary*);
animationBlock =
^(NSArray* layers, NSDictionary* parameters)
{
[CATransaction begin];
[CATransaction setCompletionBlock:
^{
for(CALayer* layer in layers)
layer.opacity = 1;
}];
CABasicAnimation* a2 = [CABasicAnimation animationWithKeyPath:@"opacity"];
a2.fromValue = [NSNumber numberWithFloat:0.];
a2.toValue = [NSNumber numberWithFloat:1.];
a2.duration = .4;
a2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
a2.fillMode = kCAFillModeBoth;
a2.removedOnCompletion = NO;
CABasicAnimation* a = [CABasicAnimation animationWithKeyPath:@"position.x"];
a.duration = .4;
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
a.fillMode = kCAFillModeBoth;
a.removedOnCompletion = NO;
CAAnimationGroup* g = [CAAnimationGroup animation];
g.animations = [NSArray arrayWithObjects:a,a2, nil];
g.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
g.fillMode = kCAFillModeBoth;
g.removedOnCompletion = NO;
CALayer* numberLayer;
CALayer* flechaLayer;
CGFloat timeOffset = 0;
for(int i = 0; i < [layers count]; i+=2)
{
numberLayer = [layers objectAtIndex:i];
flechaLayer = [layers objectAtIndex:i+1];
a2.beginTime = [_this.view.layer convertTime:CACurrentMediaTime() fromLayer:nil] + timeOffset;
[numberLayer addAnimation:a2 forKey:nil];
a2.beginTime = 0;
a.fromValue = [NSNumber numberWithFloat:flechaLayer.frame.origin.x + 100];
a.toValue = [NSNumber numberWithFloat:flechaLayer.frame.origin.x + flechaLayer.frame.size.width / 2.];
g.duration = 3;
g.beginTime = [_this.view.layer convertTime:CACurrentMediaTime() fromLayer:nil] + timeOffset + .4;
[flechaLayer addAnimation:g forKey:nil];
timeOffset += 1.5;
}
[CATransaction commit];
return 0;
};
[[AnimationFactory sharedFactory] registerAnimationBlock:animationBlock forKey:@"EnsureFlechasNutricion"];
}
如您所见,动画块中有对 _this 的引用。然后,注册块的 AnimationFactory(单例)方法是:
- (void)registerAnimationBlock:(int(^)(NSArray*, NSDictionary*))animationBlock forKey:(NSString*)key
{
int(^heapBlock)(NSArray*, NSDictionary*) = [animationBlock copy];
[self.animationBlocks setObject:heapBlock forKey:key];
[heapBlock release];
}
我的猜测是将块复制到堆中保留 MyObjectA,或者可能将块添加到 AnimationFactory 中的 NSMutableDictionary.. 但我不确定。有什么想法吗?