【问题标题】:iOS UILocalNotification's action button crashes and corrupts app dataiOS UILocalNotification 的操作按钮崩溃并损坏应用数据
【发布时间】:2016-01-27 20:24:36
【问题描述】:

我们的应用程序的小更新已发布,此版本还通过 Apple 支持将其应用程序 ID 从唯一 ID 更改为我们的团队 ID。

According to Apple,改为使用 Team ID 只会重置钥匙串访问权限,我们不使用钥匙串,因此它不会对我们的应用产生任何影响。

但自从更新发布以来,我们的一些生产用户一直在经历他们的应用数据损坏。仅当他们使用通知中心或锁定屏幕中的操作按钮响应本地通知时才会发生这种情况。它可能发生在所有支持的 iOS 版本上。

遇到这种情况的用户还有另一种症状,他们收到两个本地通知而不是一个,但应用程序只看到一个通知。此外,在使用[[UIApplication sharedApplication] cancelAllLocalNotifications] 禁用通知和取消后,这些通知仍然不会消失。

这些重复的通知是在应用程序从 App Store 更新之前安排的,但在更新后应用程序对某些用户失去了对它们的控制。这个问题详细描述in this question

最大的线索可能在于从 Apple 收到的崩溃报告 -

Incident Identifier: ED0E9C.............74B38C
CrashReporter Key:   ae05b............dbc46
Hardware Model:      iPhone4,1
Process:             MY_APP [444]
Path:                /private/var/mobile/Containers/Bundle/Application/65324..................8616/MY_APP.app/MY_APP
Identifier:          com.mycompany.myapp
Version:             X.X
Code Type:           ARM (Native)
Parent Process:      launchd [1]

Date/Time:           2015-10-27 21:45:24.24 -0500
Launch Time:         2015-10-27 21:45:20.20 -0500
OS Version:          iOS 9.1 (13B143)
Report Version:      104

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Triggered by Thread:  0

Last Exception Backtrace:
0   CoreFoundation                  0x244b3676 __exceptionPreprocess + 122 (NSException.m:162)
1   libobjc.A.dylib                 0x3582ee12 objc_exception_throw + 34 (objc-exception.mm:531)
2   CoreFoundation                  0x244b354c +[NSException raise:format:arguments:] + 100 (NSException.m:131)
3   Foundation                      0x25240bc4 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 88 (NSException.m:152)
4   UIKit                           0x28840754 -[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
5   UIKit                           0x28853a48 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke3218 + 32 (UIApplication.m:11920)
6   UIKit                           0x2883d71e -[UIApplication workspaceDidEndTransaction:] + 130 (UIApplication.m:2648)
7   FrontBoardServices              0x2c52dca2 -[FBSSerialQueue _performNext] + 226 (FBSSerialQueue.m:157)
8   FrontBoardServices              0x2c52df94 -[FBSSerialQueue _performNextFromRunLoopSource] + 44 (FBSSerialQueue.m:204)
9   CoreFoundation                  0x24476bfa __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 10 (CFRunLoop.c:1761)
10  CoreFoundation                  0x244767e8 __CFRunLoopDoSources0 + 448 (CFRunLoop.c:1807)
11  CoreFoundation                  0x24474b56 __CFRunLoopRun + 790 (CFRunLoop.c:2536)
12  CoreFoundation                  0x243c8114 CFRunLoopRunSpecific + 516 (CFRunLoop.c:2814)
13  CoreFoundation                  0x243c7f00 CFRunLoopRunInMode + 104 (CFRunLoop.c:2844)
14  UIKit                           0x28610208 -[UIApplication _run] + 520 (UIApplication.m:2489)
15  UIKit                           0x2860af10 UIApplicationMain + 140 (UIApplication.m:3665)
16  MY_APP                          0xc4972 main + 22 (main.m:14)
17  libdyld.dylib                   0x35f9d86e tlv_get_addr + 42 (threadLocalHelpers.s:310)

它的堆栈跟踪与this question 中的完全相同,当用户响应推送通知时会发生这种情况。应用加载期间的崩溃可能是应用数据损坏的原因。

从堆栈跟踪中可以看出,这次崩溃不是由我们的代码引起的,我们没有更改代码中的任何内容,在 App ID 更改之前它一直运行良好,并且发生在大约 2% 的用户身上。

这是处理通知操作按钮的代码 -

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {

    @try {
        if (notification) {
            NSDate *alarmTime = notification.userInfo ? [notification.userInfo objectForKey:@"time"] : nil;
            [logic saveAlarmTime:alarmTime takenAt:[NSDate date]];
        }
    }
    @catch (NSException *exception) {
        NSLog(@"Exception: %@", [exception description]);
    }
    @finally {
        completionHandler();
    }
}

是什么导致了这个崩溃?

(我知道它是在-[UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299) 中抛出的,问题是里面有什么导致它崩溃。)

【问题讨论】:

  • this question 有帮助吗?崩溃的堆栈跟踪与您的问题相同。您的应用程序是否有可能在用户通过推送通知打开应用程序后将用户转发到某个视图控制器,但打开此控制器是使用[window addSubview:viewController.view]; 而不是[window setRootViewController:viewController]; 执行的?这并不能解决两个通知问题,但也许这些都是 Xcode 7 错误/更新
  • 只是一个建议。检查所有观察者的通知。确保在这些 Observer 对象的 dealloc 中调用 removeObserver:。还有stackoverflow.com/questions/26371462/…
  • @anhtu 不是这种通知,我们说的是本地通知,观察者不是用来做这件事的。

标签: ios objective-c notifications uilocalnotification nsnotificationcenter


【解决方案1】:

此异常可能与最初通过操作按钮响应通知无关。此堆栈跟踪表明加载应用程序时出现问题,但有几个可能的原因,加载时应用程序崩溃的任何事情都会导致此问题。

例如,当应用加载并且其窗口没有分配根视图控制器时,可能会发生这种情况。如果使用addSubview 而不是setRootViewController 添加它,也可能发生这种情况,如here 所示。

您必须与遇到此崩溃的用户核实他们在做什么,如果他们确实只响应了本地通知操作按钮,或者他们在打开应用程序时遇到了崩溃。

【讨论】:

    【解决方案2】:

    数据损坏的原因是“数据保护”选项。它可以从 Xcode 或 iOS 开发者门户中启用,在 Identifiers -> App IDs 下。

    它具有三种状态:“完全保护”、“除非打开否则受保护”和“在首次用户验证之前受保护”。只要数据受到保护,即使是应用程序也无法访问数据。

    例如,如果在我们的例子中选择了“完全保护”,并且像通知的操作按钮这样的后台进程正在运行,Core Data 将由于权限错误而无法访问数据库。

    我仍然不确定为什么它会损坏数据,有时“权限定义”错误不会显示,但它仍然无法读取 SQLite 文件。也许它也写在文件上,但由于加密已打开,它损坏了文件。

    解决方案是选择“在首次用户验证之前受保护”或禁用数据保护。

    相关SO问题:CoreData errors/exceptions when app work in background mode

    Apple's iOS Security PDF

    【讨论】:

      【解决方案3】:

      此行导致崩溃:

      [UIApplication _runWithMainScene:transitionContext:completion:] + 2928 (UIApplication.m:3299)
      

      如果团队更改了某个应用,则该应用的唯一应用标识符也会更改,因为它是其中的一部分。本地通知使用唯一的应用标识符。所以它基本上确实是Apple的一个错误,因为iOS应该识别一个没有更多相应应用程序的通知。这也是您启动后的崩溃,但您没有获得通常使用的对象。

      盲目猜测,因为我不知道您的代码。响应本地通知时,请在继续之前检查对象和所有关联数据是否存在。你知道的,比如:

      if (object) {
          //do the stuff
      } else { 
          // do nothing
      }
      

      (比例外好得多,恕我直言...)

      关于不再属于您的通知 - 用户可以自己删除它们。只要确保你没有崩溃 - 什么都不做就可以了。通常人们会在某个时候自己删除它们,然后清理他们的通知中心。

      【讨论】:

      • 这基本上重复了原始问题中的结论,在其他部分我什至不确定它是如何相关的。 "it is basically indeed a bug by Apple" - 基于什么?
      • 我看到你没有建立连接。 1)这是一个苹果错误,因为有一个通知不属于团队的应用程序。 2) Is 也是您代码上的一个错误,因为您没有在某处处理 nil 。这就是为什么您会看到断言跳入的原因。您在代码中依赖于某些东西存在,但事实并非如此。可能通知属于您的应用,但不属于您的团队。
      • 不,所有对象在使用前都被检查为零。它甚至没有访问应用程序的代码,0xc4972 main + 22 (main.m:14) 不是我的代码,它只启动 UIApplicationMain 这是运行应用程序的 iOS 类,它在到达我的应用程序代码之前在途中的某个地方崩溃。
      • 你有一个 nil 引用,否则断言不会触发。在哪里,没有代码很难说。 gl 固定。
      • 没有根视图控制器是零。无论如何很高兴你发现了你的错误
      猜你喜欢
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 2013-09-17
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多