我的AppDelegate维护了一个活动窗口控制器的列表,以避免ARC过早释放它们。所以我有一个这样的通知处理程序:
- (void) windowWillClose: (NSNotification*) notification {
[self performSelectorOnMainThread: @selector(removeWindowControllerInMainThread:)
withObject: windowController
waitUntilDone: NO];
}
- (void) removeWindowControllerInMainThread: (id) windowController {
[windowControllers removeObject: windowController];
}我使用主线程,因为在通知线程上进行处理可能会在控制器准备就绪之前释放控制器。
现在,这工作得很好--除非当前有动画师在运行。我在一些地方通过NSAnimationContext使用动画师。我已经看过this QA了,答案是不可接受的。等待一段时间,只是为了完成动画,这真的很糟糕,也不能保证能正常工作;确实不能。我试着使用performSelector:withObject:afterDelay,即使延迟比当前动画持续时间更长,但它仍然导致动画师运行空对象。
像这样进行控制器清理的首选方法是什么?不使用NSAnimationContext,而使用NSAnimation,它有一个stopAnimation方法?
发布于 2013-02-18 03:30:49
首先,如果你的一些动画无限期地运行--或者持续很长一段时间--你必须有一种方法来阻止它们。
但是对于像视图上的隐式动画这样的东西,你可以简单地使用完成方法。
self.animating=YES;
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
[[v animator] setAlphaValue: 1];
} completionHandler:^{
self.animating=NO;
}];现在,您只需要轮询动画是否正在运行,如果动画没有运行,则继续关闭窗口。
进行轮询的一个很好的方法是设置一个具有固定延迟的计时器。如果动画仍在运行,只需重置计时器并等待另一个间隔。
或者,您可以从完成处理程序发送通知。
发布于 2013-02-18 07:29:57
我没有使用过NSAnimationContext (我一直使用NSAnimation这样做,但主要是因为历史原因)。但我喜欢管理类似于此的典型方式是创建短暂的保留循环。
Mark的回答完全正确,但不需要进行投票。在完成处理程序中引用self这一事实意味着self不能在完成处理程序运行之前解除分配。事实上,你是否读过animating并不重要。ARC必须保持您的位置,直到完成块运行,因为该块引用了您。
另一种类似的技术是使用objc_setAssociatedObject将自己附加到动画上下文。这将保留您,直到完成块运行。在完成块中,删除self作为关联对象,然后您就可以自由释放。这种方法的好处是它不需要像animating这样虚假的额外属性。
当然,最后一种偶尔合适的孤注一掷的措施是创建短暂的自我引用。例如:
- (void)setImmortal:(BOOL)imortal {
if (immortal) {
_immortalReference = self;
}
else {
_immortalReference = nil;
}
}我并不是在提倡最后一种选择。但知道它的存在是件好事,更重要的是知道它为什么会起作用。
https://stackoverflow.com/questions/14925066
复制相似问题