试图用未知的演示者解除 UIAlertController

Posted

技术标签:

【中文标题】试图用未知的演示者解除 UIAlertController【英文标题】:Trying to dismiss UIAlertController with unknown presenter 【发布时间】:2015-04-15 11:38:56 【问题描述】:

我的应用程序崩溃了,一定是因为 UIAlertController。

此问题仅在 UIAlertController 可用的 ios 8.x 上发生。奇怪的事实是我的应用程序既不使用 UIAlertViewController 也不使用 UIAlertView

报告告诉我:

Trying to dismiss UIAlertController <UIAlertController: 0x172c5d80> with unknown presenter.

这怎么会发生?

我想过

    由于摇晃手势而显示的 System AlertView 撤消 当提示或通用对话框仍在屏幕上时,WebView 被释放 低电量警报

但没有一个案例让我陷入崩溃。

崩溃日志对我的建议是,操作系统显示了一个 AlertView,它将附加到我的应用程序窗口,并且在某些情况下会丢失显示 UIAlertViewController 的父视图控制器。

任何想法如何找到问题?

这里是堆栈跟踪

_________________________________
0    CoreFoundation                         0x2bc0c45f __exceptionPreprocess + 127
1    libobjc.A.dylib                        0x39c79c8b objc_exception_throw + 36
2    CoreFoundation                         0x2bc0c3a5 +[NSException raise:format:] + 110
3    UIKit                                  0x2f4ad13d -[UIAlertController _dismissAnimated:triggeringAction:triggeredByPopoverDimmingView:] + 414
4    UIKit                                  0x2f4acf97 -[UIAlertController _dismissAnimated:triggeringAction:] + 28
5    UIKit                                  0x2f590a0b -[_UIAlertControllerActionView touchesEnded:withEvent:] + 160
6    UIKit                                  0x2f159567 -[UIWindow _sendTouchesForEvent:] + 520
7    UIKit                                  0x2f152e31 -[UIWindow sendEvent:] + 542
8    UIKit                                  0x2f129759 -[UIApplication sendEvent:] + 194
9    UIKit                                  0x2f39d2f9 _UIApplicationHandleEventFromQueueEvent + 14166
10   UIKit                                  0x2f1281a9 _UIApplicationHandleEventQueue + 1350
11   CoreFoundation                         0x2bbd2fbf __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
12   CoreFoundation                         0x2bbd23cf __CFRunLoopDoSources0 + 216
13   CoreFoundation                         0x2bbd0a35 __CFRunLoopRun + 770
14   CoreFoundation                         0x2bb1e3b1 CFRunLoopRunSpecific + 474
15   CoreFoundation                         0x2bb1e1c3 CFRunLoopRunInMode + 104
16   GraphicsServices                       0x3308d201 GSEventRunModal + 134
17   UIKit                                  0x2f18843d UIApplicationMain + 1438
18   MyApp                                  0x00028a07 main (main.mm:16)

编辑

holes 询问我的窗口初始化。这是我的 AppDelegate 的代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    self.window = [[MyAppCustomWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    _mainViewController = [[MyAppContainerViewController alloc] initWithNibName:nil bundle:nil];
    _mainStatusBarVC = [[MyAppStatusBarVC alloc] initWithRootVC:_mainViewController];

    [self.window setRootViewController:_mainStatusBarVC];
    [self.window makeKeyAndVisible];

    return YES;

【问题讨论】:

您是如何为您的应用初始化 UIWindow 实例的? 我在我的 AppDelegate 应用程序中初始化了 MyCustomWindow:didFinishLaunchingWithOptions: 然后我设置了 rootViewController 并使用 self.window makeKeyAndVisible 使其成为键和可见。我将用一些关于它的代码来编辑问题。 添加了有关 MyCustomWindow 初始化的代码。我有兴趣重现该问题,以确保任何类型的代码修复都可以肯定地解决该问题。我不知道为什么 UIAlertViewController 会显示在我的应用程序堆栈跟踪中。 从你的介绍中我看不出来。一定是有其他原因造成的。 完全正确...我错过了显示此系统警报的内容。必须是一个以某种方式干扰我的应用程序的系统进程,但我无法弄清楚。 【参考方案1】:

我打赌你的崩溃发生在 iPad 上。

在 iPad 上,从 iOS8 开始,UIActionSheet 似乎使用UIAlertController 处理

使用此代码,

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 
    if(buttonIndex == 1) return; // Cancel button

    [self doSomeViewControllerDismisses];

我的应用因与您遇到的相同错误而崩溃。 为了防止这种情况,我只是在下一次 MainThread 执行时调度复杂的解除调用,给隐藏的UIAlertViewController 正确释放的机会。

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 
    if(buttonIndex == 1) return; // Cancel button

    dispatch_async(dispatch_get_main_queue(), ^
        [self doSomeViewControllerDismisses];
    );

【讨论】:

感谢马丁的提示。不幸的是,我的应用根本不使用 UIActionSheet 您的应用是否使用弹出框 (UIPopoverController)?我认为 Apple 开发人员在其他几个 UIKit 控件中重用了这个 UIAlertController,比如弹出框。 是的,我使用它。我会检查的。【参考方案2】:

此表单的堆栈跟踪通常表明您已离开 UIViewController,而您拥有它的警报仍在解除。

解决这个问题的一般方法是在 UIAlertViewDelegate 的 alertView:didDismissWithButtonIndex: 方法中显示或关闭控制器,这样您就可以确定在任何关闭期间演示者都不会离开。

在您的情况下,如果您找不到任何可重现的情况,您可以尝试在呈现/关闭控制器之前检查presentedViewController,看看是否有任何问题。

但是,如果您审核控制器转换,您可能会发现响应系统警报的某个地方可能会以编程方式触发导航。您是否有任何功能会为用户授权引发系统警报,例如访问照片或其他任何内容,并且他们否认它会导致控制器被您的错误处理以编程方式解雇?这似乎是一个相当合理的场景。

【讨论】:

正如我所写的,我的整个代码根本不使用 UIAlertViewController。我无法访问源代码的唯一第三方库是批评。我实验过,在同样的情况下,不知道何时,crittercism 会向用户发出位置跟踪确认警报。因为我不知道 Crittercism 库何时尝试访问它,所以我自己尝试模拟 crittercism 可能的 LocationManager 所有权,如下一条评论中所述。 MyAppDelegate 保留 locationManager,而模态呈现的 viewController 请求授权使用位置功能。这会导致显示系统跟踪警报。现在我可以通过我的应用程序上可用的远程功能来关闭模态控制器。这将导致模式视图控制器在跟踪警报仍在屏幕上时关闭。点击警报、取消或允许的两个按钮中的任何一个,我的应用程序仍然可以运行,没有任何不良后果。 无论如何,根据您的回答,我还有另一个问题。您确定使用显示系统弹出窗口的 iOS SDK API,作为位置跟踪或照片访问,我可以在当前显示的视图控制器上找到 UIViewController 检查presentedViewController 吗?我不这么认为......我现在没有测试它,但我觉得很奇怪,我必须在自己的代码中关心 iOS 自己生成的东西。当然,这可能是 iOS 8 的错误,但如果我感到惊讶的是,我在使用 iOS 8 的 iOS 设备上运行的数千个应用程序中从未遇到过它。 在任何正常情况下,都不应该。但是,由于您很确定崩溃的警报控制器不是您的,所以我对它如何生成所提供的崩溃日志的“合理合理”的猜测是,它变得混乱并使用您的一个控制器消失了,而不是无论它应该呈现什么。【参考方案3】:

尝试使用 Block on main thrad 在主线程 Alertview 上关闭。

dispatch_async(dispatch_get_main_queue(),  () -> Void in
  //  Write your alert view code in swift language .
)

【讨论】:

问题是,如果 myApp 根本不使用 UIAlertController,myApp 怎么会在 UIAlertController 上崩溃……

以上是关于试图用未知的演示者解除 UIAlertController的主要内容,如果未能解决你的问题,请参考以下文章

如何设置PPT中的”演示者视图”

Android MVP - 应该避免在演示者中使用 R.string 引用吗?

应该将演示者(mvP)注入(dagger2)到android中的视图吗?

OnetoOne 未知映射者

在 MVP 模式中,了解活动/上下文的演示者是不是是个坏主意?

模型视图演示者 - 相同的视图,不同的演示者