7

そのため、プレゼンテーション層のキャッシングと思われる興味深い問題に直面しており、他の人がこれを見ているかどうか、またどのような回避策があるかを考えています.

暗黙的にアニメーション化している独自のプロパティがいくつかあります。プロパティとして宣言し、動的に合成することでこれを行っています。

@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();
}

出力:

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

2 番目のケースでは、アクションを無効にして、単一の値の更新を取得します。これで問題ありません。

- (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

2回目:

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 presentationLayer] を呼び出す 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 呼び出しを追加する方法に注意してください。

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

4

2 に答える 2

10

にアクセスしませんでしたpresentationLayerが、今日も同じ問題が発生しました。

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

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

これらのコミットを再び機能させる 2 つの方法を見つけましたが、マイナスの副作用がありました。

  1. を使用してすべてのレイヤーの変更をフラッシュすると、すべてのレイヤーが+[CATransaction flush]更新され、期待どおりに機能します。presentationLayer+[CATransaction begin…commit]
  2. を使用して暗黙的なトランザクションをコミットする+[CATransaction commit]と、同じ結果が得られます。

しかし、それをするとすぐに、アプリ全体で他のランダムな問題が発生しました. 一部のビューは、正しくレイアウトされ、呼び出されたにもかかわらず、単に表示されませんdrawRect:でした。UIView深く掘り下げていくと、 とそのバッキングCALayerが頻繁に同期していないことに気付きました。

presentationLayer自分のやりたいことをに頼るのが間違っているという結論に達しました。

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

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

-[CALayer display]レイヤ コンテンツpresentationLayerの提供の例が示すように、はレイヤの値にのみアクセスし、 の値にはアクセスしないでください。ユーザーが現在見ているものから開始するアニメーションは、の値を として使用できます。presentationLayerfromValue

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

于 2013-01-14T10:39:47.800 に答える
1

を使用して同様の問題を修正できました[CATransaction setCompletionBlock:

実行ループが完了して更新できるようにしましたpresentationLayer

于 2014-05-30T03:06:08.657 に答える