2012-04-12 3 views
1

私は4th ed。 Hillegass/Preble Cocoaの本の中で、Core Animationで理解できない問題を抱えています。CATransaction begin/commit inループは尊重されません。すべては一度に起こります。

とりわけ、私は、レイヤーホスティングビューに画像のリストを1つずつ表示する次のループを持っています。予想される結果は、presentImageが呼び出されるたびに、各画像が1枚ずつ飛び散るのを見るはずです。実際の結果は、ループが完了してからイメージが一度に飛び出すまで、ビューは空のままです。遅れている間、私はpresentImageへの複数の呼び出しを示す複数のログメッセージを見る。これらのログメッセージが停止すると、ループが完了したことを示し、すべてのイメージが一度に飛びます。

// loop to present each image in list of URLs 
// called at end of applicationDidFinishLaunching 
NSTimeInterval t0 = [NSDate timeIntervalSinceReferenceDate]; 
for(id url in urls) { 
    NSImage *img = [[NSImage alloc] initWithContentsOfURL:url]; 
    if(!img) 
     continue; 

    NSImage *thumbImg = [self thumbImageFromImage:img]; 

    [self presentImage:thumbImg]; 

    NSString *dt = [NSString stringWithFormat:@"%0.1fs", 
        [NSDate timeIntervalSinceReferenceDate]-t0]; 

    NSLog(@"Presented %@ at %@ sec",url,dt); 
} 

thumbImageFromImageの方法は、(小さい画像を作成する)と思っています。次のようにpresentImageためのコードは次のとおり[CATransaction begin][CATransaction commit]コールがpresentImage内部addSublayerへの呼び出しではなく、forループブラケットているかのよう

- (void)presentImage:(NSImage *)image 
{ 
    CGRect superlayerBounds = view.layer.bounds; 
    NSPoint center = NSMakePoint(CGRectGetMidX(superlayerBounds), CGRectGetMidY(superlayerBounds)); 

    NSRect imageBounds = NSMakeRect(0, 0, image.size.width, image.size.height); 

    CGPoint randomPoint = CGPointMake(CGRectGetMaxX(superlayerBounds)*(double)random()/(double)RAND_MAX, CGRectGetMaxY(superlayerBounds)*(double)random()/(double)RAND_MAX); 

    CAMediaTimingFunction *tf = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

    CABasicAnimation *posAnim = [CABasicAnimation animation]; 
    posAnim.fromValue = [NSValue valueWithPoint:center]; 
    posAnim.duration = 1.5; 
    posAnim.timingFunction = tf; 

    CABasicAnimation *bdsAnim = [CABasicAnimation animation]; 
    bdsAnim.fromValue = [NSValue valueWithRect:NSZeroRect]; 
    bdsAnim.duration = 1.5; 
    bdsAnim.timingFunction = tf; 

    CALayer *layer = [CALayer layer]; 
    layer.contents = image; 
    layer.actions = [NSDictionary dictionaryWithObjectsAndKeys:posAnim,@"position", bdsAnim, @"bounds", nil]; 

    [CATransaction begin]; 
    [view.layer addSublayer:layer]; 
    layer.position = randomPoint; 
    layer.bounds = NSRectToCGRect(imageBounds); 
    [CATransaction commit]; 
} 

観察結果です。実際には、と[CATransaction commit]presentImageの内側から削除して、代わりにforループを括弧で囲むと、同じような動作を繰り返します。実際には、[CATransaction begin][CATransaction commit]の呼び出しをすべて削除すると、同じ一度に実行される動作を観察します。

答えて

3

良い質問です。あなたが見ていることは、エクササイズがどのように構築されているかを考えれば、期待されることです。その理由は、レイヤーのアニメーション(および描画)が、現在画像のロードおよびサムネイルの作成で占められているメインスレッドで行われるためです。すべての画像がロードされてサムネイルが作成されてから、メインスレッドが実際にあなたが要求したアニメーションを実行することができるまでではありません。 CATransactionは、この単一スレッドのコンテキストで大きな影響を受けません。

次の章(34、同時実行性)では、バックグラウンドスレッド(NSOperationQueueを使用)でイメージを準備することでこれを改善します。これにより、メインスレッドは新しいイメージを表示し、各イメージがバックグラウンドで読み込まれ、サイズが変更されるとアニメーションが実行されます。

+0

ありがとう、アダム。それは有り難いです。私はその行動が少なくとも誰かによって期待されることを嬉しく思います:-)。私はそれが非常に奇妙なことを見つける。 'for(id url in urls)'ループの各繰り返しは、どのスレッドが作業を行っているかにかかわらず、イメージをロードし、そのイメージのプレゼンテーションをアニメートする必要があります。 'CATransaction'呼び出しが無視されるかもしれないことは、コードや' CATransaction'文書のどちらかからわかりません。私はすぐにその文書をもっと慎重に読むでしょう。 – JefferyRPrice

+0

私は彼らが無視されているとは言いませんが、メインスレッドはアニメーションのような他のイベントを処理する機会を得ていないので、 addImagesFromFolderURL:を返します。これは、Cocoa(および他のフレームワーク)に注意する共通のものです。UIが更新してユーザの入力に応答できるように、メインスレッドが再開できるようにします。 –

+0

もう一度ありがとう!しかし、私はConcurrencyの章を終えたので、私はまだ混乱していると言わなければなりません。すべての画像は一度に表示されますが、より高速です(2.0秒対3.0秒)。 UIは、1つのアニメーションだけをコミットしたかのように、一度にすべてを更新します。私にとっては、ループを通過するたびに複数のアニメーションをコミットしたようです。イメージを1つずつ表示させるにはどうすればいいですか? (私は 'applicationDidFinishLaunching'の' addImagesFromFolderURL'を動かして、代わりにボタンのターゲットにしました)。 – JefferyRPrice

0

まあ、このバグを数週間は私の中に残した後、ここには意味があるように見えますが、(私には)幾分明らかです。

上記の私の最初の質問で与えられたコードから、メインスレッドはアニメーションを含むすべてのUI更新を担当しますが、presentImageが完了するまでメインスレッドは効果的にUIの更新をブロックされます。これは、presentImageをどのようにスレッドに分割するかにかかわらず(Ch 34のように)当てはまります。

たとえば、上記のコードのようにループの代わりにボタンのターゲットとしてpresentImageが呼び出された場合、ボタンをクリックするとすぐに各アニメーションが開始され、私はボタンをクリックします。これは、私が期待していた(そして私が誤って元のものと思っていた)複数の同時アニメーションで終わってしまいます。

正式な技術情報を正確に取得したかどうかはわかりませんが、これは少なくとも答えとして私を満たしています。

関連する問題