2013-01-10 4 views
7

プレゼンテーションレイヤーのキャッシングと思われるものがいくつか興味深い問題にぶつかりつつあり、他の人がこれを見ているのか、どのような対処法ができるのか不思議です。CoreAnimationがプレゼンテーションレイヤのコピーをキャッシュしているように見えるのはなぜですか?

暗黙的にアニメーション化されている独自のプロパティがいくつかあります。これが正常に動作します

@interface GOOLayer : CALayer 
@property float gooValue; 
@end 

NSString *const kGOOLayerValueKey = @"gooValue"; 

@implementation GOOLayer 

@dynamic gooValue; 

- (id)initWithLayer:(id)layer { 
    if ((self = [super initWithLayer:layer])) { 
    id value = [layer valueForKey:kGOOLayerValueKey]; 
    [self setValue:value forKey:kGOOLayerValueKey]; 
    } 
    return self; 
} 

- (id<CAAction>)actionForKey:(NSString *)event { 
    id <CAAction> action = [super actionForKey:event]; 
    if (action == nil && [event isEqual:kGOOLayerValueKey]) { 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event]; 
    animation.fromValue = [self.presentationLayer valueForKey:event]; 
    animation.duration = [CATransaction animationDuration]; 
    return animation; 
    } 
    return action; 
} 

- (void)display { 
    GOOLayer *presoLayer = [self presentationLayer]; 
    NSLog(@"Display GooValue: %f", presoLayer.gooValue); 
} 

+ (BOOL)needsDisplayForKey:(NSString *)key { 
    if ([key isEqual:kGOOLayerValueKey]) { 
    return YES; 
    } 
    return [super needsDisplayForKey:key]; 
} 

ほとんどのケースでは、我々は適切な値が記録されて参照してください。私たちは、プロパティとして宣言すると、動的にそれらを合成することでこれをやっています。 は、最初のケースでは、我々は適切な暗黙のアニメーションを取得:

- (IBAction)doSomeGoo:(id)sender { 
    sublayer_.gooValue = random(); 
} 

出力:第2のケースで

2012-12-19 10:10:41.440 CoreAnimation[94149:c07] Display GooValue: 1804289408.000000 
2012-12-19 10:10:41.502 CoreAnimation[94149:c07] Display GooValue: 1804289408.000000 
... 
2012-12-19 10:10:41.739 CoreAnimation[94149:c07] Display GooValue: 898766464.000000 
2012-12-19 10:10:41.757 CoreAnimation[94149:c07] Display GooValue: 846930880.000000 

、私たちはアクションを無効にするので、私たちは結構です、単一の値の更新を取得する:

- (IBAction)doSomeGoo2:(id)sender { 
    long newValue = random(); 
    NSLog(@"newValue = %f", (float)newValue); 
    [CATransaction begin]; 
    [CATransaction setDisableActions:YES]; 
    sublayer_.gooValue = newValue; 
    [CATransaction commit]; 
} 

初回通過:

2012-12-19 10:11:16.208 CoreAnimation[94149:c07] newValue = 1714636928.000000 
2012-12-19 10:11:16.209 CoreAnimation[94149:c07] Display GooValue: 1714636928.000000 
通じ

セカンド時間:

2012-12-19 10:11:26.258 CoreAnimation[94149:c07] newValue = 1957747840.000000 
2012-12-19 10:11:26.259 CoreAnimation[94149:c07] Display GooValue: 1957747840.000000 

それは私たちが面白いです、トランザクションを実行する前に、私達はちょうど[CALayerのプレゼンテーション層]呼び出した第3のケースです:

- (IBAction)doSomeGoo3:(id)sender { 
    GOOLayer *presoLayer = sublayer_.presentationLayer; 
    long newValue = random(); 
    NSLog(@"presoLayer.gooValue = %f newValue = %f", presoLayer.gooValue, (float)newValue); 
    [CATransaction begin]; 
    [CATransaction setDisableActions:YES]; 
    sublayer_.gooValue = newValue; 
    [CATransaction commit]; 
} 

初回通過:

2012-12-19 10:12:12.505 CoreAnimation[94149:c07] presoLayer.gooValue = 1957747840.000000 newValue = 424238336.000000 
2012-12-19 10:12:12.505 CoreAnimation[94149:c07] Display GooValue: 1957747840.000000 

2回目:

2012-12-19 10:12:13.905 CoreAnimation[94149:c07] presoLayer.gooValue = 424238336.000000 newValue = 719885376.000000 
2012-12-19 10:12:13.906 CoreAnimation[94149:c07] Display GooValue: 424238336.000000 

presentationLayer呼び出しを追加すると、displayが現在の値を取得しないようになります。

これに対処する方法についての提案、または私が事を完全に誤解している場合はこれが予想される動作ですか?

答えて

9

私はにアクセスしませんでしたが、今日でも同じ問題が発生しています。

UIScrollViewのスクロールバーが表示されるたびに、一部のアニメーションが意図したとおりに機能しませんでした。 CATransactionに関連する問題であり、presentationLayerにアクセスすることに時間がかかりました。

presentationLayerにアクセスすると、現在のrunloopサイクルが終了するまで、CATransactionは明示的なトランザクションのコミットを無視(または遅延)させます。メッセージのログを見ると、明示的なトランザクションのための+[CATransaction commit]は、presentationLayerがANYレイヤーにアクセスされるとすぐにノーオペレーションになります。

これらのコミットをもう一度行うには2つの方法がありますが、負の副作用があります。 +[CATransaction flush]を使用して、すべてのレイヤの変更をフラッシュ

  1. は、すべての層のpresentationLayerを更新し、期待通り+[CATransaction begin…commit]作業を行います。
  2. +[CATransaction commit]を使用して暗黙的なトランザクションをコミットすると、同じ結果が得られます。

しかし、私がやってすぐに、アプリ全体で他のランダムな問題が発生しました。一部のビューは正しくレイアウトされていても表示されず、drawRect:も呼び出されました。 もっと深くなっていくと、UIViewとその背中CALayerが頻繁に同期しなくなっていることがわかりました。

presentationLayerに私がしたかったことを私が間違っていると結論づけました。

Appleのドキュメントの記事Core Animation Rendering Architectureは、ユーザーに現在表示されているように、presentationLayerにすべての値があることを明確にしています。アニメーションの有無にかかわらず、変更はrunloopサイクルが終了するまで(または通常は暗黙の外部CATransactionがフラッシュ/コミットされるまで)presentationLayerに反映されず、すべてのレイヤの変更がユーザに提示されます。

私のアニメーションは同じランループサイクル内でレイヤーに加えられた変更に依存しているため、これらの変更はまだユーザーには表示されず、したがってpresentationLayerでは利用できません。

-[CALayer display]Providing Layer Contentの例のように、そのレイヤの値にのみアクセスし、そのレイヤの値にはアクセスしないでください。presentationLayer。 ユーザーが現在表示しているものから開始する必要があるアニメーションはとしてpresentationLayerの値を使用できます。

まだ発生しているその他の問題は、レンダリングアーキテクチャを誤った方法で使用している可能性が最も高いです。 presentationLayerの代わりにレイヤの現在の状態を使用するようにアニメーションを再考します。

+1

感謝を完了し、更新することができ[CATransaction setCompletionBlock:

を使用して、同様の問題を解決することができました。 [Core Animation Rendering Architecture](https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/CoreAnimationArchitecture.html#//apple_ref/doc/uid/TP40006655-SW1)の状態明示的に "アニメーションの処理中にCALayerのインスタンスに対応するプレゼンテーションレイヤーを問い合わせることができます。これは、現在のアニメーションを変更し、現在表示されている状態から新しいアニメーションを開始する場合に最も便利です。 私たちが見ていることを考えれば、これは間違っているようです。 – dmaclach

+0

私はこの声明がまだ有効だと思います。 // displayを呼び出すと、その時点でユーザーに表示されるgooValueが出力されます。 // 前のpresentationLayerを照会する最後の例では、現在のrunloopサイクルが終了して変更がユーザーにすぐに見えなくなるまで、暗黙的なトランザクションが発生すると考えられます。 // 何かが実際にレンダリングされてユーザに提示されたとき(画面更新)には、現在のランループサイクルまたは出力の数を表示するためにテストを拡張する必要があります。 – fluidsonic

1

私は実行ループがコメント@fluidsonicためpresentationLayer

関連する問題