2

UITableViewCell でアニメーションを実行します。各セルには独自のアニメーションがあり、セルは再利用可能です。私が使う[mView performSelectorInBackground:@selector(layoutSubview) withObject:nil];

バックグラウンド スレッドで runLoop を開始して、次のようなタスクを実行します。

- (void)startAnimation 
{
    NSRunLoop *mLoop = [NSRunLoop currentRunLoop];
    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(setNeedsDisplay) userInfo:nil repeats:YES];

    mRunLoop = YES;
    while (mRunLoop == YES && [mLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]);
}

そしてそれを止めます:

- (void)stopAnimation 
{
    if (![NSThread isMainThread]) {
        [[NSThread currentThread] cancel];
    }

    mRunLoop = NO;
    self.animationTimer = nil;
    CFRunLoopStop(CFRunLoopGetCurrent());   
}

テーブルを高速スクロールすると問題が発生します。これは、最初のセルの開始時にアニメーションを開始するため、最初の runLoop 呼び出しが発生して setNeedDisplay とそこからすべてのメソッドが実行されるためです。しかし、最初の runLoop サイクルが終了する前に、セルはビューから消え、すでに再利用可能になっています。それで、サイクルがまだ操作を実行している間に、それをクリアし始めます。ここで、次のような状況に遭遇します

割り当て解除されたインスタンスに送信されたメッセージ

そのスレッドでの操作の実行を正しく停止するにはどうすればよいか、ヒントを教えてください。たとえば、いくつかのアクションを実行しているオブジェクトを実現したい場合、すぐに停止する方法はありますか?

十分な情報を提供したことを願っています。ありがとう

更新:まったくアイデアがありませんか?

4

4 に答える 4

2

私はそれに完全に異なる刺し傷を取ります:

セルのタイマーとバックグラウンドスレッドを完全に取り除きます!

アニメーションはNSTimer、そもそも適切なものではなく、複数のタイマーを使用してもあまり役に立ちません。

UITableViewメソッドvisibleCellsとメソッドがありindexPathsForVisibleRowsます。テーブルビューコントローラーとそのディスプレイリンクのコールバックで、ディスプレイの実際のリフレッシュレートまたはその一部でコールバックするため、アニメーションに適したシングルを使用することをCADisplayLinkお勧めします。目に見える細胞。

セカンダリスレッドの実行ループでdisplay-linkをスケジュールする場合は、自由にスケジュールしてください。ただし、最初に余分なスレッドを使用せずに回避できるかどうかを確認します。

いくつかのコード:

@interface AnimatedTableViewController ()

@property (strong, nonatomic) CADisplayLink *cellAnimator;
- (void)__cellAnimatorFired:(CADisplayLink *)animator;

@end

@implementation AnimatedTableViewController

@synthesize cellAnimator = cellAnimator_;

- (void)setCellAnimator:(CADisplayLink *)animator
{
    if (animator == cellAnimator_)
        return;

    [cellAnimator_ invalidate];
    cellAnimator_ = animator;

    [cellAnimator_ addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSCommonRunLoopModes];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    self.cellAnimator = [CADisplayLink displayLinkWithTarget:self selector:@selector(__cellAnimatorFired:)];
    ...
}

- (void)viewWillDisappear:(BOOL)animated
{
    self.cellAnimator = nil;
    ...

    [super viewWillDisappear:animated];
}

- (void)__cellAnimatorFired:(CADisplayLink *)animator
{
     NSArray *visibleCells = [self.tableView visibleCells];
     [visibleCells enumerateObjectsUsingBlock:^(UITableViewCell *cell, NSUInteger unused, BOOL *stop){
         [cell setNeedsDisplay];
     }];
}

...

@end
于 2011-12-26T15:04:48.757 に答える
2

NSTimer には-cancel、タイマーの起動を停止するメソッドがあります。それを呼び出すと-prepareForReuse(さらに言えば、で-stopAnimation)役立つ場合があります。

ただし、このコードはかなり危険に見えます。このように実行ループを入れ子にすることは、ほとんど良い考えではありません。戻し-startAnimationても、アニメーション タイマーは引き続きメインの実行ループで実行されます。そして、-startAnimation遅延させたいコードが後にあるためにこのようにしている場合は、コードを再構築して、これが不要になるようにする必要があります。

(runloop を にドロップした場合は、いずれか-startAnimationで runloop を停止しないでください-stopAnimation。)

danyowdeeが推奨するアプローチのようなものはさらに良いでしょうが、少なくともこのランループのものを取り除きます. トラブルを求めているだけです。

于 2011-12-28T11:08:25.623 に答える
0

この方法を問題に使用できると思います

[NSObject cancelPreviousPerformRequestsWithTarget:yourTarget selector:aSelector object: anArgument];

于 2011-12-20T05:19:40.087 に答える
0

その振る舞いを回避する最善の方法は、cancel メソッドを受け取るデリゲートを、再利用されない別のクラスに割り当てることだと思います。たとえば、すべてのキャンセル メソッドを処理するインスタンスのプライベート配列を作成し、各行を配列要素にマップすることができます。

Apple が Xcode ドキュメントで提供している遅延テーブルの例をお勧めします。これは、テーブルを使用してバックグラウンドで非同期に画像を読み込む方法の良い例です。スクロールの対象(減速とページング)にも役立つと思います。

もう 1 つだけ考慮事項があります。いくつかの cfrunloopstop を台無しにすることはお勧めしません。一生懸命テストしてください。

于 2011-12-28T10:40:34.807 に答える