CADisplayLink 目标选择器在失效后被触发
我有一个 CADisplayLink 可以触发 Director 对象中的 draw
方法。我想要使 CADisplayLink 无效,然后释放 Director 对象使用的一些单例 Cache 对象。 draw
方法不会保留单例 Cache 对象。
在Director中名为stopAnimation
的方法中(该方法与draw
方法无关),我这样做:
[displayLink invalidate];
然后我开始释放单例Cache对象,但随后CADisplayLink触发并最后一次调用 draw
方法。 draw
方法尝试访问已释放的单例对象,但一切都崩溃了。
这种情况只会在某些时候发生:有时应用程序不会崩溃,因为 Cache 对象在 displayLink 实际上失效且绘制方法已经完成运行后被释放。
在使 displayLink 无效后,如何检查绘制方法是否已完成运行并且不会再次触发,以便安全地使 Cache 对象无效?如果可能的话,我不想修改 draw
方法。
我尝试了多种组合,包括使用
[self PerformSelectorOnMainThread:@selector(stopAnimation) withObject:self waitUntilDone:YES]
在主线程上执行 displayLink invalidate
或尝试执行它在 currentRunLoop 中使用
[[NSRunLoop currentRunLoop] PerformSelector:@selector(stopAnimation) target:self argument:nil order:10 models:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
但结果总是一样的,有时它释放共享缓存太早了。
我也不想使用具有任意延迟的 performSelector:withObject:afterDelay:
方法。我想确保 displayLink 无效,绘制方法结束,并且不会再次运行。
I have a CADisplayLink that triggers a draw
method in a Director object. I want to invalidate the CADisplayLink and then deallocate some singleton Cache objects that are used by the Director object. The singleton Cache objects are not retained by the draw
method.
In a method called stopAnimation
in the Director (this method is unrelated to the draw
method), I do:
[displayLink invalidate];
and then I start releasing the singleton Cache objects, but then the CADisplayLink fires and the draw
method gets called one last time. The draw
methods tries to access the deallocated singleton objects and everything crashes.
This only happens sometimes: there are times in which the app doesn't crash because the Cache objects are released after the displayLink is actually invalidated and the draw method has already finished running.
How can I check, after invalidating the displayLink, that the draw method has finished running and that it won't fire again, in order so safely invalidate the Cache objects? I don't want to modify the draw
method if possible.
I tried a number of combinations, including performing displayLink invalidate
on the main thread using
[self performSelectorOnMainThread:@selector(stopAnimation) withObject:self waitUntilDone:YES]
or trying to perform it in the currentRunLoop by using
[[NSRunLoop currentRunLoop] performSelector:@selector(stopAnimation) target:self argument:nil order:10 modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
but the results is always the same, sometimes it releases the shared Caches too early.
I also don't want to use the performSelector:withObject:afterDelay:
method with an arbitrary delay. I want to make sure the displayLink is invalidated, that the draw method ended, and that it won't be run again.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(2)
问题在于,即使在 CADisplayLink
从运行循环模式中释放后,CALayer
的 display()
仍会继续被调用。
如果在运行循环正在执行处理程序例程的过程中触发计时器,则计时器会等到下一次通过运行循环时调用其处理程序例程。
防止层在调用 invalidate()
后更新的最面向未来的方法是子类 CALayer
,添加一个标志,并在 invalidate() 旁边更改标志
,并在调用 super.display()
之前检查标志的值。
class Layer: CALayer {
var shouldDisplay: Bool = true
override func display() {
if shouldDisplay {
super.display()
}
}
}
因此,在使显示链接无效的同时,请将图层的 shouldDisplay
设置为 false。这将阻止子类继续重新加载该层的内容,无论哪个线程调用 invalidate()
。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
这可能有点晚了,但由于没有答案...
我不认为您的选择器被再次调用,而是显示链接的线程位于您的绘制框架方法的中间。无论如何,问题都是一样的。这是多线程,尝试在一个线程中释放某些对象,同时在另一个线程中使用它们通常会导致冲突。
也许最简单的解决方案是在您的并条机方法中放置一个标志和一个“if 语句”,
然后无论您在何处使显示链接无效,都将“schaduledForDestruction”设置为 YES。
如果您确实认为显示链接再次调用该方法,则可以在该方法内使用另一个“destructionInProgress”。
如果你不想改变绘制框架方法,你可以尝试强制一个新的选择器到显示链接......
或者只是考虑这样的事情(但我不能说这是安全的。如果新创建的显示链接可以在与原始线程不同的线程上运行选择器,它没有解决任何问题)..
This might be a bit late but since there has been no answers...
I do not think, your selector is called once more, but rather the display link's thread is in the middle of your draw frame method. In any case, the problem is quite the same.. This is multithreading and by trying to dealloc some objects in one thread while using them in another will usually result in a conflict.
Probably the easiest solution would be putting a flag and an "if statement" in your draw frame method as
and then wherever you are invalidating your display link set "schaduledForDestruction" to YES.
If you really think the display link calls tis method again, you could use another if inside that one "destructionInProgress".
If you do not want to change the draw frame method, you could try forcing a new selector to the display link...
or just consider something like this (but I can't say this is safe. If the newly created display link can run the selector on a different thread then the original, it solves nothing)..