[編集: 混乱を招いていたため、このケース全体では ARC ではなく MRR を想定しています]
自分自身を (間接的に) 参照し、別のオブジェクトのプロパティにコピーされる (つまり、オブジェクト As のスタックからコピーされる) ブロックで奇妙な動作をしています (明らかに説明がありますが、それを理解することはできません)。ヒープに保存され、オブジェクトによって保持されます B)。ブロックに _this への参照が含まれていない場合、オブジェクト A の dealloc は、ナビゲーション コントローラーからポップされるたびに呼び出されます。ただし、ブロックが _this を参照する場合、オブジェクト (以下のコードでは MyObjectA) の dealloc は 1 回おきにしか呼び出されません。つまり、このビュー コントローラー サブクラスをプッシュし、createBlock を呼び出し、ポップしても何も起こりません。私はもう一度プッシュし、createBlock が再び呼び出され、次にポップし、MyObjectA で dealloc を呼び出します。
簡潔にするために、動作の鍵と思われるスニペットのみを掲載しています。
次のように、createBlock メソッドを含むオブジェクト MyObjectA (カスタム UIViewController のサブクラス) があるとします。
- (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 に追加される可能性がありますが、よくわかりません。何かご意見は?