我想按顺序呈现多个模态视图(例如,从图像选择器中选择图片后显示确认页面)。我的问题是,在没有延迟的后续步骤中解雇和呈现的动画总是会使用EXC_BAD_ACCESS
使应用程序崩溃。
我认为问题在于CoreAnimation
没有区分两个转换,并且无法正确检测第一个转换是否已经结束。
到目前为止,我的工作是引入1段延迟,似乎可以解决问题。但是,我认为这会使代码有点脆弱。还有另一种解决方法吗?
这是UIKit中的错误吗?我应该提交错误报告吗?
示例代码
这是一个重现崩溃的简单案例:
使用以下类创建一个新的基于视图的项目作为主控制器的实现
出现图像选择器视图时点击'取消'
预期行为:由于viewDidAppear
中的后续调用,选择器视图被解除并再次显示。
实际行为:它与下面显示的堆栈跟踪崩溃。
代码:
#import "SampleViewController.h"
@implementation SampleViewController
- (void)showModal {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[self presentModalViewController:picker animated:YES];
// [picker release];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self showModal]; // this line crashes the app
// the following works as desired
// [self performSelector:@selector(showModal) withObject:nil afterDelay:1];
}
@end
崩溃堆栈跟踪:
#0 0x30b43212 in -[UIWindowController transitionViewDidComplete:fromView:toView:] #1 0x3095828e in -[UITransitionView notifyDidCompleteTransition:] #2 0x3091af0d in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] #3 0x3091ad7c in -[UIViewAnimationState animationDidStop:finished:] #4 0x00b54331 in run_animation_callbacks #5 0x00b54109 in CA::timer_callback #6 0x302454a0 in CFRunLoopRunSpecific #7 0x30244628 in CFRunLoopRunInMode #8 0x32044c31 in GSEventRunModal #9 0x32044cf6 in GSEventRun #10 0x309021ee in UIApplicationMain #11 0x00002794 in main at main.m:14
答案 0 :(得分:8)
您需要让动画上下文完成。正如您已经发现的那样
[self performSelector:@selector(showModal)withObject:nil afterDelay:1];
有效,但很明显,延迟并不好,所以这样做:
[self performSelector:@selector(showModal) withObject:nil afterDelay:0.0];
当你使用afterDelay:0.0它不会直接调用选择器,而是将你的runloop上的调用排入队列,这会让你所有的状态(自动释放池,动画上下文等)都正确地调用,然后立即调用你的调用runloop开始处理事件。
可能出现问题的一个问题是,用户可以通过点击屏幕来关闭UIEvents,但是你可以通过在动画启动之前调用它来解决这个问题
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
这一旦你在屏幕上有你的最终模态
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
通常,您希望在动画快速过渡时花费UI交互。