9

drawDirector オブジェクトのメソッドをトリガーする CADisplayLink があります。CADisplayLink を無効にしてから、Director オブジェクトが使用するシングルトン キャッシュ オブジェクトの割り当てを解除したいと考えています。シングルトン Cache オブジェクトは、drawメソッドによって保持されません。

Director で呼び出されるメソッドstopAnimation(このメソッドはメソッドとは関係drawありません) で、次のことを行います。

[displayLink invalidate];

次に、シングルトン Cache オブジェクトの解放を開始しますが、CADisplayLink が起動し、drawメソッドが最後にもう一度呼び出されます。メソッドはdraw、割り当てが解除されたシングルトン オブジェクトにアクセスしようとし、すべてがクラッシュします。

これはたまにしか発生しません。displayLink が実際に無効になり、draw メソッドの実行が既に終了した後に Cache オブジェクトが解放されるため、アプリがクラッシュしない場合もあります。

Cache オブジェクトを安全に無効にするために、displayLink を無効にした後、draw メソッドの実行が終了し、再度呼び出されないことを確認するにはどうすればよいですか? draw可能であれば、メソッドを変更したくありません。

displayLink invalidateを使用してメインスレッドで実行するなど、いくつかの組み合わせを試しました

[self performSelectorOnMainThread:@selector(stopAnimation) withObject:self waitUntilDone:YES]

または使用して currentRunLoop で実行しようとしています

[[NSRunLoop currentRunLoop] performSelector:@selector(stopAnimation) target:self argument:nil order:10 modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];

ただし、結果は常に同じで、共有キャッシュの解放が早すぎる場合があります。

performSelector:withObject:afterDelay:また、任意の遅延でメソッドを使用したくありません。displayLink が無効になっていること、draw メソッドが終了していること、および再度実行されないようにしたいと考えています。

4

2 に答える 2

8

これは少し遅いかもしれませんが、答えがないので...

セレクターがもう一度呼び出されるとは思いませんが、表示リンクのスレッドは描画フレームメソッドの途中にあります。いずれにせよ、問題はまったく同じです。これはマルチスレッドであり、あるスレッドでオブジェクトを使用しているときに別のスレッドでオブジェクトの割り当てを解除しようとすると、通常は競合が発生します。

おそらく最も簡単な解決策は、次のように描画フレーム メソッドにフラグと「if ステートメント」を入れることです。

if(schaduledForDestruction) {
[self destroy];
 return;
}

次に、表示リンクを無効にする場所はどこでも、「schaduledForDestruction」をYESに設定します。

表示リンクが tis メソッドを再度呼び出すと本当に思っている場合は、その「destructionInProgress」内で別のメソッドを使用できます。

フレームの描画方法を変更したくない場合は、新しいセレクターを表示リンクに強制することができます...

CADisplayLink *myDisplayLink;
BOOL resourcesLoaded;
SEL drawSelector;

- (void)destroy {    
    if(resourcesLoaded) {
        [myDisplayLink invalidate];
        //free resources
        resourcesLoaded = NO;
    }    
}
- (void)metaLevelDraw {
    [self performSelector:drawSelector];
}
- (void)drawFrame {
    //draw stuff
}
- (void)beginAnimationing {
    drawSelector = @selector(drawFrame);
    myDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(metaLevelDraw)];
    [myDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)endAnimationing {
    drawSelector = @selector(destroy);
}

または、このようなことを検討してください(ただし、これが安全だとは言えません。新しく作成された表示リンクが元のスレッドとは異なるスレッドでセレクターを実行できる場合、何も解決しません)。

CADisplayLink *myDisplayLink;
BOOL resourcesLoaded;

- (void)destroy {    
    if(resourcesLoaded) {
        [myDisplayLink invalidate];
        //free resources
        resourcesLoaded = NO;
    }    
}
- (void)drawFrame {
    //draw stuff
}
- (void)beginAnimationing {
    myDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame)];
    [myDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)endAnimationing {
    [myDisplayLink invalidate];
    myDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(destroy)];
    [myDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
于 2011-11-30T15:52:16.543 に答える