当展示模态视图控制器时,iPhone 崩溃了。

31

我试图在另一个视图以模态方式呈现后立即显示一个模态视图(第二个是出现的加载视图)。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Show load
    LoadViewController *loader = [[LoadViewController alloc] init];
    [self presentModalViewController: loader animated:NO];
    [loader release];
}

但是当我这样做时,我会收到一个“Program received signal: "EXC_BAD_ACCESS"。”的错误。

堆栈跟踪如下:

0  0x30b43234 in -[UIWindowController transitionViewDidComplete:fromView:toView:]
1  0x3095828e in -[UITransitionView notifyDidCompleteTransition:]
2  0x3091af0d in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
3  0x3091ad7c in -[UIViewAnimationState animationDidStop:finished:]
4  0x0051e331 in run_animation_callbacks
5  0x0051e109 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 0x00002154 in main at main.m:14

有什么想法吗?我完全被卡住了!加载视图为空,所以肯定没有任何操作会导致错误。是因为在同一事件循环中模态地启动了两个视图还是其他原因呢?

谢谢,

迈克

编辑:非常奇怪......我稍微修改了一下,让加载视图在微小的延迟后显示,这个方法可以正常工作!所以它似乎是在同一事件循环中的某些问题!

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Show load
    [self performSelector:@selector(doit) withObject:nil afterDelay:0.1];
}

- (void)doit {
    [self presentModalViewController:loader animated:YES];  
}

EXC_BAD_ACCESS到底是从哪里来的?你在这里给了我们一个堆栈跟踪,但我不确定错误是否发生在这段代码中。能不能编辑帖子,给我们所有线程在哪里的完整日志和跟踪呢? - Gordon Seidoh Worley
我不确定它来自哪里。这是我唯一的线索,看起来坏的访问并不是来自我的代码,所以它是内部访问某些东西,所以我无法确定它!我已经确保了所有内容都被保留,所以我不知道发生了什么! - Michael Waterfall
尝试将loader放入自动释放池中。我认为loader消失得太快了,可能是因为当前的视图控制器必须为新的视图和视图控制器让路。其他想法:使用调试器并观察loader。如果它是引起问题的原因,你会通过这种方式发现它。如果不是,请继续在调试器中探索,你可能会找到答案。 - Gordon Seidoh Worley
好的,我会尝试一下。我该如何在调试器中观察加载器?是通过使用断点吗?还是有其他监视事物的方法?如果有其他调试方式,我很感兴趣! - Michael Waterfall
我认为循环的原因是你正在加载的新视图控制器默认具有viewDidAppear方法,并且它具有[super viewdidappear animated];这意味着它将再次调用回到您的主视图控制器的viewDidAppear,就像这样循环进行。 - NSGodMode
16个回答

30

我稍微修改了一下,使得加载视图在延迟后显示,这样就可以正常工作了!所以看起来问题出在同一事件循环中!

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Show load
    [self performSelector:@selector(doit) withObject:nil afterDelay:0.1];
}

- (void)doit {
    [self presentModalViewController:loader animated:YES];  
}

1
哥们,我已经试了好一阵子了还是搞不明白。谢谢你的帮助! - Justin Gallagher
2
我怀疑使用0.0f的延迟也能够正常工作。基本上,它将在下一次运行循环迭代中呈现,几乎是即时的。 - Thomas Müller
1
如果这个修复方法对某些人不起作用,我发现如果你意外地快速连续调用presentModalViewController,也会出现这个错误消息。 - Chazbot
1
即使延迟5秒,它仍然会崩溃。 - zakdances
这在视图控制器的viewDidLoad方法实现中也完美地工作。谢谢Michael。 - user3117509
显示剩余3条评论

5
我相信我在iOS 4中复制了同样的错误。在我的应用程序中,在显示第一个模态视图后立即尝试显示第二个模态视图时,崩溃会一直发生。我为此苦苦挣扎了几个小时。
阅读了这个帖子后,我尝试使用选项卡应用程序模板创建一个简单的可重现示例。我能够在“FirstViewController.m”中响应按钮点击后使用UIImagePickerController显示第一个模态视图。当我再次尝试显示UIImagePickerController(在处理imagePickerControllerDidCancel消息后),应用程序会崩溃并显示相同的错误。
在设备上,根本没有线索。但是,当我在模拟器上运行代码时,我很幸运地在控制台上获得了以下消息:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempting to begin a modal transition from to while a transition is already in progress. Wait for viewDidAppear/viewDidDisappear to know the current transition has completed'
因此,我的唯一选择似乎是遵循错误消息的建议,并等待viewDidAppear(使用标志表示我处于此特殊模式中),然后加载第二个模态视图。
完整的堆栈跟踪如下:
**首次抛出异常的调用堆栈:
(
 0   CoreFoundation                      0x0238c919 __exceptionPreprocess + 185
 1   libobjc.A.dylib                     0x024da5de objc_exception_throw + 47
 2   CoreFoundation                      0x02345078 +[NSException raise:format:arguments:] + 136
 3   Foundation                          0x000ab8cf -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116
 4   UIKit                               0x00544317 -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:] + 212
 5   UIKit                               0x0035c769 -[UIViewController presentModalViewController:withTransition:] + 2937
 6   TestTempDelete                      0x000021cf -[FirstViewController showImagePicker] + 167
 7   Foundation                          0x0002fcea __NSFireDelayedPerform + 441
 8   CoreFoundation                      0x0236dd43 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
 9   CoreFoundation                      0x0236f384 __CFRunLoopDoTimer + 1364
 10  CoreFoundation                      0x022cbd09 __CFRunLoopRun + 1817
 11  CoreFoundation                      0x022cb280 CFRunLoopRunSpecific + 208
 12  CoreFoundation                      0x022cb1a1 CFRunLoopRunInMode + 97
 13  GraphicsServices                    0x02bf12c8 GSEventRunModal + 217
 14  GraphicsServices                    0x02bf138d GSEventRun + 115
 15  UIKit                               0x002beb58 UIApplicationMain + 1160
 16  TestTempDelete                      0x00001eb4 main + 102
 17  TestTempDelete                      0x00001e45 start + 53

希望这有所帮助。


4

正如前面所说的那样,使用 isIgnoringInteractionEvents

//Check if the app is ignoring interatctions, if so, add a delay for 1 sec
if([[UIApplication sharedApplication] isIgnoringInteractionEvents]==TRUE) {
        [currentViewController performSelector:@selector(presentModalViewController:animated:) withObject:screen afterDelay:1];
    } else {
        [currentViewController presentModalViewController:screen animated:YES];
    }

这在我的情况下有效...但我不确定它如何正确传递“animating”标志...很可能它被设置为一些垃圾值,恰好是非零的。 - Kendall Helmstetter Gelner
救命稻草!! :) 如果想从后台方法呈现视图,这个很有效。 - Azhar Bandri

3

我遇到了相同的异常

由于正在进行转换,因此终止应用程序出现未捕获的异常 'NSInternalInconsistencyException',原因:'尝试从到开始模态转换,而转换已经在进行中。等待viewDidAppear/viewDidDisappear来了解当前转换何时完成'

如之前建议的那样,我尝试延迟呈现模态转换,但这并没有真正帮助。然后我发现我有多个 IBActions 连接到我的按钮的 TouchUpInside 事件!!!在我的情况下,两个 IBActions 将启动:模态地呈现一个人员选择器和模态地呈现一个图像选择器。这解释了错误消息。检查您是否连接了多个 IBActions!


3

如果您在点击与代码相关联的按钮后看到此消息,那么可能是因为您将两个操作链接到了同一个按钮上(例如,如果您将模态视图链接到按钮上,然后复制了该按钮并链接另一个模态视图)。这将尝试同时触发它们,因此会失败并显示该消息。


1

我认为这个问题与我遇到的问题有关。 很容易就能重现:

创建新的XCode项目“实用程序应用程序”。在FlipsideViewController.m中, 您只需要插入以下方法:

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear: animated];
  [self showInfo];
}

如果您这样做,启动应用程序,那么反面视图将立即被激活。一旦您在反面视图上按下“完成”按钮,您将返回到主视图,再次触发viewDidAppear并立即返回到反面视图。一旦反面视图显示出来,应用程序停止运行 - 没有内存释放器被调用 - 就像您按下了主屏幕按钮。

当我在这些视图中使用一些附加属性时,我也遇到了异常问题,因此我将代码削减到最小限度...

我真的不知道这个问题是什么...

最好的问候, 托比亚斯


1

我遇到了同样的问题,这是由于名称不匹配导致的

HelpViewController *controller = [[HelpViewController alloc] initWithNibName:@"HelpView" bundle:nil];

以及实际 .xib 文件的名称。


1
当我点击一个UIButton来打开一个模态视图时,遇到了类似的错误。我将UIButton的监听器从UIControlEventAllEvents更改为UIControlEventTouchUpInside。基本上,它在Touch Down Inside上触发模态视图,然后又在Touch Up Inside上触发一次。

好的答案。为了概括一下:注意打开模态视图的代码,并确保它仅调用一次。不一定要来自按钮点击。 - Tal Bereznitskey

1

你的问题很可能出现在初始化和展示viewDidAppear方法的方法中,或者是LoadViewController的init/viewDidLoad/viewWillAppear方法中。

设置一些断点并跟踪直到崩溃...


这些方法基本上是空的。我所做的就是在viewDidLoad:中更改背景颜色。应用程序可以正常执行这些行,崩溃不是发生在我的代码中,而是在事件循环后面执行其他操作时崩溃的。 - Michael Waterfall

0

我认为循环的原因是您正在加载的新视图控制器默认具有viewDidAppear方法,它有

[super viewDidAppear animated];

这意味着它会再次调用您的主视图控制器的viewDidAppear方法,就像这样循环进行。

在您正在呈现的视图控制器中,如果没有超级视图didAppear方法,则会出现以下方法:

-(void)viewDidAppear:(BOOL)animated{
    //[super viewDidAppear:animated]; no super

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接