应用程序因未捕获的异常而终止,异常名称为“NSInternalInconsistencyException”,原因是“意外的起始状态”。

15

我遇到了一个奇怪且不易重现的崩溃问题,它发生在iOS 9上。问题是如何修复此问题是什么导致了这个异常

正如您所看到的,跟踪日志不包含我的代码,并且崩溃发生在应用程序启动时。

Last Exception Backtrace:
0   CoreFoundation                       0x0000000180a49900 __exceptionPreprocess + 124
1   libobjc.A.dylib                      0x00000001800b7f80 objc_exception_throw + 52
2   CoreFoundation                       0x0000000180a497d0 +[NSException raise:format:arguments:] + 104
3   Foundation                           0x00000001813bca08 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 84
4   UIKit                                0x00000001859f9f34 _prepareForCAFlush + 252
5   UIKit                                0x00000001859ff4f0 _beforeCACommitHandler + 12
6   CoreFoundation                       0x0000000180a00588 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 28
7   CoreFoundation                       0x00000001809fe32c __CFRunLoopDoObservers + 368
8   CoreFoundation                       0x00000001809fe75c __CFRunLoopRun + 924
9   CoreFoundation                       0x000000018092d680 CFRunLoopRunSpecific + 380
10  GraphicsServices                     0x0000000181e3c088 GSEventRunModal + 176
11  UIKit                                0x00000001857a4d90 UIApplicationMain + 200
12  MyAppName                            0x000000010009d200 main (main.m:14)
13  ???                                  0x00000001804ce8b8 0x0 + 0

Thread 0 Crashed:
0   libsystem_kernel.dylib               0x00000001805ec140 __pthread_kill + 8
1   libsystem_pthread.dylib              0x00000001806b4ef8 pthread_kill + 108
2   libsystem_c.dylib                    0x000000018055ddac abort + 136
3   MyAppName                            0x0000000100805bcc uncaught_exception_handler + 28
4   CoreFoundation                       0x0000000180a49c88 __handleUncaughtException + 648
5   libobjc.A.dylib                      0x00000001800b823c _objc_terminate() + 108
6   libc++abi.dylib                      0x00000001800aaf44 std::__terminate(void (*)()) + 12
7   libc++abi.dylib                      0x00000001800aab10 __cxa_rethrow + 140
8   libobjc.A.dylib                      0x00000001800b8120 objc_exception_rethrow + 40
9   CoreFoundation                       0x000000018092d728 CFRunLoopRunSpecific + 548
10  GraphicsServices                     0x0000000181e3c088 GSEventRunModal + 176
11  UIKit                                0x00000001857a4d90 UIApplicationMain + 200
12  MyAppName                            0x000000010009d200 main (main.m:14)
13  ???                                  0x00000001804ce8b8 0x0 + 0

调试器控制台在堆栈跟踪之前会输出什么内容? - Dennis Pashkov
你的意思是什么?这是崩溃报告日志的一部分。 - sage444
你能在 Xcode 调试时重现这个崩溃吗? - Dennis Pashkov
2
看一下 stack 中的这行代码:3 Foundation 0x00000001813bca08 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 84。在调试模式下,你会看到一个消息“Assertion failed in ...”。它至少可以帮助你识别出错误的源文件。 - Dennis Pashkov
你最终解决了这个问题吗?我也遇到了同样的情况。 - Evan R
显示剩余2条评论
2个回答

4

我遇到了同样的崩溃,错误信息是 reason: 'unexpected start state'

原因如下:

  • 我在tableView中的一个单元格里放置了一个按钮,并将其标题设置为电子邮件地址。当按下该按钮时,我需要打开邮件应用程序。

  • 当它打开邮件应用程序时,我的视图控制器(其中包含tableView)正在重新加载traitCollectionDidChange中的表格。 这个tableView.reloadData()很可能导致崩溃,因为应用程序处于活动状态和后台之间的过渡状态。

解决方法如下:

  • 使用回调函数来处理按下电子邮件按钮的事件:
class NewsDetailsFooterCell: UITableViewCell {

    //MARK: - Callbacks
    var sendEmail: ((_ emailUrl: URL) -> ())?

    //MARK: - IBActions
    @IBAction func openAuthorEmail(_ sender: UIButton) {

        guard let emailAddress = sender.titleLabel?.text, let url = URL(string: "mailto:\(emailAddress)") else { return }
        guard UIApplication.shared.canOpenURL(url) else { return }
        self.sendEmail?(url)
    }
}

在tableView的cellForRowAt中使用了回调并修改了一个本地变量,该变量负责在traitCollectionDidChange函数中阻止tableView的reloadData:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let newsFooterCell = tableView.dequeueReusableCell(withIdentifier: "NewsDetailsFooterCell") as! NewsDetailsFooterCell
            //other cell setup

    newsFooterCell.sendEmail = { [weak self] emailUrl in
        self?.viewModel.canReloadTable = false //this is the variable which I need to modify here
        UIApplication.shared.open(emailUrl, options: [:], completionHandler: nil)
    }
    return newsFooterCell
}

traitCollectionDidChange中,我只有当变量canReloadTable为真时才重新加载表格数据:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
   super.traitCollectionDidChange(previousTraitCollection)

   if #available(iOS 12.0, *) {
       //using this delegate method to trigger data reload to adapt to Dark/Light modes
       guard viewModel.canReloadTable else { return }
       tableView.reloadData()
   }
}
  • 最后,我在viewDidAppear中将变量canReloadTable设置回true
   override func viewDidAppear(_ animated: Bool) {
       super.viewDidAppear(animated)

       viewModel.canReloadTable = true
   }

我希望这个答案能够帮助其他人,或者至少能够给出一个线索,指引大家在研究潜在问题时进行调查。由于错误本身并没有提供任何描述性信息,所以我花费了大约1-2小时的时间来研究它,并得出了一个解决方案。


1
我也遇到了同样的问题。通过添加dispatchque.main.async { self.tableView.reloadData()},我成功解决了它。 - undefined

4

当更改应用程序主题时,在 traitCollectionDidChange 中重新加载 UICollectionView 时遇到相同的问题。

我有一个方法 updateTheme(),当主题改变时,我会更新一些 UI,如层、边框、阴影等。

  override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    if #available(iOS 13.0, *), traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
      updateTheme()
    }
  }

我将收到有关终止的此类消息:

*** Assertion failure in void _UIApplicationDrainManagedAutoreleasePool()(), UIApplication+AutoreleasePool.m:171
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unexpected start state'

updateTheme()方法中添加collectionView.reloadData()时会出现这种情况。

当应用程序最小化并更改主题时会发生这种情况。很有趣的情况,因为所有视图、按钮、标签等都能正常工作,但是集合却不行。

通常,如果UI元素在后台线程中得到更新,应用程序会崩溃,因此每当我们想要更新UI时,我们需要在主线程中更新该UI元素。

我敢假设,当应用程序最小化时,traitCollectionDidChange方法不在主线程中执行,因此您需要添加DispatchQueue.main.async {}以便在主线程中更新UI。

这个更改对我解决了问题,我希望它也能帮助到您,因为您添加的简单标志,在我的情况下,当应用程序最小化时更改主题将根本不允许界面更新。

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    if #available(iOS 13.0, *), traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
      DispatchQueue.main.async {
        self.updateTheme()
      }
    }
  }

这也是个好主意!没有测试过,但听起来是合理的。 - Starsky

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