CADisplayLink目标选择器在失效后触发

Ric*_*aez 9 cocos2d-iphone ios cadisplaylink

我有一个CADisplayLink触发drawDirector对象中的方法.我想使CADisplayLink无效,然后取消分配Director对象使用的一些单独的Cache对象.draw方法不保留单例Cache对象.

stopAnimationDirector中调用的方法(此方法与方法无关draw),我做:

[displayLink invalidate];
Run Code Online (Sandbox Code Playgroud)

然后我开始发布单例Cache对象,但随后启动了CADisplayLink,draw最后一次调用该方法.这些draw方法试图访问解除分配的单例对象,一切都崩溃了.

这种情况有时只会发生:有时候应用程序不会崩溃,因为在displayLink实际失效并且draw方法已经完成运行后释放了Cache对象.

在使displayLink无效之后,我如何检查draw方法是否已经完成运行并且它不会再次触发,以便安全地使Cache对象无效?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]];

但结果总是一样的,有时它会过早地释放共享的Caches.

我也不想使用performSelector:withObject:afterDelay:任意延迟的方法.我想确保displayLink无效,draw方法结束,并且不会再次运行.

Mat*_*lak 8

这可能有点晚,但由于没有答案......

我不认为,你的选择器再次被调用,而是显示链接的线程在你的绘制框架方法的中间.在任何情况下,问题都是完全相同的.这是多线程的,并且通过尝试在一个线程中释放一些对象而在另一个线程中使用它们通常会导致冲突.

可能最简单的解决方案是在你的并条方法中放置一个标志和一个"if语句"

if(schaduledForDestruction) {
[self destroy];
 return;
}
Run Code Online (Sandbox Code Playgroud)

然后,无论您将显示链接集"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);
}
Run Code Online (Sandbox Code Playgroud)

或者只考虑这样的事情(但我不能说这是安全的.如果新创建的显示链接可以在不同的线程上运行选择器然后原始,它什么也解决不了)..

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];
}
Run Code Online (Sandbox Code Playgroud)