向 UNUserNotificationCenter 添加大量触发器时跳板崩溃

Springboard crashing when adding a lot of triggers to UNUserNotificationCenter

将自己从数小时的调试中解救出来,因为我刚刚浪费了 2 周的时间来寻找神秘的应用程序崩溃问题。事实证明,如果您向 UNUserNotificationCenter 添加大量 o(有关更多详细信息,请参见答案)通知请求,它会突然使 Springboard 崩溃。我还没有找到解决这个问题的方法,因为相同的代码适用于 iOS 9 及以下版本。您似乎也无法像以前那样批量添加通知请求。以下是我每次都会收到的崩溃(数百个应用程序用户也是如此)。知道我可以做什么而不是回到使用 UILocalNotifications 吗?

Incident Identifier: 17BC9D5B-AF74-4592-8427-038375C27AE7
CrashReporter Key:   a819553d1e72ee25a5ced9ddc79dbf00a7d3851f
Hardware Model:      iPad5,3
Process:             SpringBoard [2371]
Path:                /System/Library/CoreServices/SpringBoard.app/SpringBoard
Identifier:          com.apple.springboard
Version:             50 (1.0)
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           com.apple.springboard [71]


Date/Time:           2016-11-16 14:57:04.9159 +0400
Launch Time:         2016-11-16 14:49:20.9981 +0400
OS Version:          iPhone OS 10.0 (14A5309d)
Report Version:      104

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

Filtered syslog:
None found

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   GraphicsServices                0x0000000182396198 GSEventRunModal + 180
6   UIKit                           0x00000001869327c8 -[UIApplication _run] + 664
7   UIKit                           0x000000018692d534 UIApplicationMain + 208
8   libdyld.dylib                   0x00000001805305b8 start + 4

Thread 1 name:  com.apple.uikit.eventfetch-thread
Thread 1:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   Foundation                      0x000000018142ce3c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   Foundation                      0x000000018144d92c -[NSRunLoop(NSRunLoop) runUntilDate:] + 96
7   UIKit                           0x000000018727af2c -[UIEventFetcher threadMain] + 136
8   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
9   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
10  libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
11  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 2:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   Foundation                      0x000000018142ce3c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   Foundation                      0x0000000181481584 -[NSRunLoop(NSRunLoop) run] + 88
7   UIKit                           0x0000000186f73298 -[UIStatusBarServerThread main] + 840
8   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
9   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
10  libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
11  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 3:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   Foundation                      0x000000018142ce3c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   CoreBrightness                  0x0000000190ec5d10 -[BrightnessSystemClientInternal main] + 1392
7   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
8   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
9   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
10  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 4:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   SpringBoard                     0x00000001001a0b00 0x1000f0000 + 723712
6   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
7   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
8   libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 5 name:  com.apple.springboard.icongeneration
Thread 5:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   SpringBoard                     0x00000001001a0c00 0x1000f0000 + 723968
6   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
7   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
8   libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 6 name:  com.apple.CoreMotion.MotionThread
Thread 6:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   CoreFoundation                  0x00000001809dd094 CFRunLoopRun + 112
6   CoreMotion                      0x0000000187762994 0x187702000 + 395668
7   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
8   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
9   libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 7 name:  SBWiFiManager callback thread
Thread 7:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   Foundation                      0x000000018142ce3c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   Foundation                      0x0000000181481584 -[NSRunLoop(NSRunLoop) run] + 88
7   SpringBoard                     0x0000000100215e44 0x1000f0000 + 1203780
8   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
9   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
10  libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
11  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 8:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   Foundation                      0x000000018142ce3c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   HomeKit                         0x00000001913e8974 -[_HMLocationHandler createLocationManager] + 508
7   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
8   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
9   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
10  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 9:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   Foundation                      0x000000018142ce3c -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   CoreBrightness                  0x0000000190ec5d10 -[BrightnessSystemClientInternal main] + 1392
7   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
8   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
9   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
10  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 10 name:  CommonUtilities-WiFi-Thread
Thread 10:
0   libsystem_kernel.dylib          0x0000000180624194 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x0000000180624004 mach_msg + 72
2   CoreFoundation                  0x0000000180a61e8c __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x0000000180a5faa8 __CFRunLoopRun + 1132
4   CoreFoundation                  0x000000018098f8d8 CFRunLoopRunSpecific + 444
5   CoreFoundation                  0x00000001809dd094 CFRunLoopRun + 112
6   CommonUtilities                 0x0000000182d10c20 0x182d0a000 + 27680
7   Foundation                      0x00000001815293ac __NSThread__start__ + 1024
8   libsystem_pthread.dylib         0x00000001807079ec _pthread_body + 240
9   libsystem_pthread.dylib         0x00000001807078fc _pthread_body + 0
10  libsystem_pthread.dylib         0x0000000180704ef8 thread_start + 4

Thread 11:
0   libsystem_kernel.dylib          0x0000000180642a88 __workq_kernreturn + 8
1   libsystem_pthread.dylib         0x000000018070549c _pthread_wqthread + 1440
2   libsystem_pthread.dylib         0x0000000180704ef0 start_wqthread + 4

Thread 12:
0   libsystem_kernel.dylib          0x0000000180642a88 __workq_kernreturn + 8
1   libsystem_pthread.dylib         0x000000018070549c _pthread_wqthread + 1440
2   libsystem_pthread.dylib         0x0000000180704ef0 start_wqthread + 4

Thread 13 name:  Dispatch queue: com.apple.frontboard.sqlite.database
Thread 13 Crashed:
0   libsystem_kernel.dylib          0x0000000180642014 __pthread_kill + 8
1   libsystem_pthread.dylib         0x00000001807094f0 pthread_kill + 112
2   libsystem_c.dylib               0x00000001805b64b8 abort + 140
3   libsystem_malloc.dylib          0x0000000180686a38 _nano_vet_and_size_of_live + 0
4   libsystem_malloc.dylib          0x0000000180687db8 nano_free + 220
5   libsqlite3.dylib                0x000000018103a5f8 0x180f95000 + 677368
6   libsqlite3.dylib                0x0000000180fbac9c 0x180f95000 + 154780
7   libsqlite3.dylib                0x0000000180fe6074 0x180f95000 + 331892
8   libsqlite3.dylib                0x0000000180fd70b0 sqlite3_step + 588
9   FrontBoard                      0x0000000190312ee4 __79-[_FBSqlitePreparedSimpleStatement executeWithBindings:resultRowHandler:error:]_block_invoke + 424
10  libdispatch.dylib               0x00000001804fd784 _dispatch_client_callout + 16
11  libdispatch.dylib               0x000000018050aca4 _dispatch_barrier_sync_f_invoke + 84
12  FrontBoard                      0x000000019031e0d0 -[FBSqliteDatabaseConnection performSyncWithDatabase:] + 80
13  FrontBoard                      0x0000000190312cbc -[_FBSqlitePreparedSimpleStatement executeWithBindings:resultRowHandler:error:] + 148
14  FrontBoard                      0x000000019035a4d8 -[FBSqliteApplicationDataStoreRepository _dbQueue_executeStatement:bindings:resultRowHandler:error:] + 80
15  FrontBoard                      0x000000019035a538 -[FBSqliteApplicationDataStoreRepository _dbQueue_executeStatement:bindings:resultRowHandler:] + 72
16  FrontBoard                      0x0000000190359374 -[FBSqliteApplicationDataStoreRepository _dbQueue_objectForKey:forApplication:] + 504
17  FrontBoard                      0x0000000190357a34 __81-[FBSqliteApplicationDataStoreRepository objectForKey:forApplication:withResult:]_block_invoke.44 + 40
18  libdispatch.dylib               0x00000001804fd784 _dispatch_client_callout + 16
19  libdispatch.dylib               0x000000018050aca4 _dispatch_barrier_sync_f_invoke + 84
20  FrontBoard                      0x0000000190357990 -[FBSqliteApplicationDataStoreRepository objectForKey:forApplication:withResult:] + 92
21  FrontBoard                      0x000000019038a5cc -[FBApplicationDataStoreInProcessRepositoryClient objectForKey:forApplication:withResult:checkPrefetch:] + 528
22  FrontBoardServices              0x00000001825c3e3c __40-[FBSApplicationDataStore objectForKey:]_block_invoke + 112
23  libdispatch.dylib               0x00000001804fd784 _dispatch_client_callout + 16
24  libdispatch.dylib               0x0000000180508f80 _dispatch_block_invoke_direct + 376
25  BaseBoard                       0x00000001825415a8 -[NSObject(BaseBoard) bs_performSynchronously:timeout:] + 144
26  FrontBoardServices              0x00000001825c3d7c -[FBSApplicationDataStore objectForKey:] + 224
27  FrontBoardServices              0x00000001825c4044 -[FBSApplicationDataStore safeObjectForKey:ofType:] + 32
28  FrontBoardServices              0x00000001825c41d4 -[FBSApplicationDataStore archivedObjectForKey:] + 64
29  FrontBoardServices              0x00000001825c4314 -[FBSApplicationDataStore safeArchivedObjectForKey:ofType:] + 32
30  UserNotificationsServer         0x000000019c52169c -[UNSPendingNotificationRepository _pendingNotificationDictionariesForBundleIdentifier:] + 140
31  UserNotificationsServer         0x000000019c5219d0 -[UNSPendingNotificationRepository setPendingNotificationRecords:forBundleIdentifier:] + 72
32  UserNotificationsServer         0x000000019c5249b4 -[UNSLocalNotificationClient _setPendingNotificationRecords:] + 500
33  UserNotificationsServer         0x000000019c5235c4 -[UNSLocalNotificationClient addPendingNotificationRecords:] + 1124
34  UserNotificationsServer         0x000000019c51d648 -[UNSNotificationSchedulingService _queue_addPendingNotificationRecords:forBundleIdentifier:] + 84
35  UserNotificationsServer         0x000000019c51c6b0 __108-[UNSNotificationSchedulingService addPendingNotificationRecords:forBundleIdentifier:withCompletionHandler:]_block_invoke + 36
36  libdispatch.dylib               0x00000001804fd7c4 _dispatch_call_block_and_release + 24
37  libdispatch.dylib               0x00000001804fd784 _dispatch_client_callout + 16
38  libdispatch.dylib               0x000000018050b880 _dispatch_queue_serial_drain + 928
39  libdispatch.dylib               0x0000000180500f6c _dispatch_queue_invoke + 652
40  libdispatch.dylib               0x000000018050bd7c _dispatch_queue_override_invoke + 360
41  libdispatch.dylib               0x000000018050d718 _dispatch_root_queue_drain + 572
42  libdispatch.dylib               0x000000018050d478 _dispatch_worker_thread3 + 124
43  libsystem_pthread.dylib         0x00000001807053f8 _pthread_wqthread + 1276
44  libsystem_pthread.dylib         0x0000000180704ef0 start_wqthread + 4

UPDATE: 好像不是根据具体的通知数量来的。我只是碰巧经常触发它,因为我在应用程序处于后台时注册了大约 30 到 40 个通知(推送通知、应用程序刷新、应用程序进入后台等)——因为异步添加这些警报需要比平时更长的时间,该应用程序将同时释放它持有的后台任务标识符。我在下面详细解释了这一点以及解决方法。

此错误已被 Apple 确认并标记为与先前报告的错误重复。我希望这个问题得到解决,因为它在某些边缘情况下继续导致问题,在这些情况下,应用程序在后台启动并在不久之后超时(在后台内容刷新期间)。

我找到了解决方法(已使用 Apple 错误 ID 29286162 记录错误)

本质上,如果 UNUserNotificationCenter 正忙于添加通知并且尚未完成添加,而用户按下主页按钮 return 到 SpringBoard,SpringBoard 似乎会崩溃。显然,不知何故线程快要死了(好吧,可能是因为我必须放弃后台任务标识符,希望 UNUserNotificationCenter 会在其自己的系统提供的后台线程中愉快地使用传递的请求),留下 on - 在 limbo 中进行异步操作,导致 Springboard 最终崩溃。我现在只是在后台任务 (UIBackgroundTaskIdentifier) 中生成一个线程并坚持下去,直到它完成添加所有通知。这导致零崩溃 - 之前抱怨相同的所有用户也证实了这一点。

  // arrTasksToSchedule -> holds UNNotificationRequests to add

  __block NSInteger volatile processedAlerts = 0;
  NSInteger totalToProcess = [arrTasksToSchedule count];
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  for (UNNotificationRequest* notifRequest in arrTasksToSchedule) {
    [center addNotificationRequest:notifRequest withCompletionHandler:^(NSError * _Nullable error) {
      processedAlerts++;
    }];
  }

  // Let the runloop carry on processing events till we're done
  while (processedAlerts != totalToProcess) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
  }

  // Okay we're done, and can now let go of our held UIBackgroundTaskIdentifier  

文档没有提到后台任务、在后台任务中使用 UNUserNotificationCenter 的风险或与多线程有关的任何事情等。我只能假设他们没有意识到大多数应用程序在以下时间进行通知注册他们的应用程序被发送到后台(或在后台内容刷新推送通知期间)。

由于 Springboard 崩溃了 - 没有为应用程序本身生成崩溃报告。用户一直在抱怨,这是您毫无头绪的极其困难的情况之一。我希望这可以让一些人省去很多麻烦。

更新: 虽然上面的代码现在工作得很好,但我做了一些小修改,因为如果用户关闭应用程序,while 循环的条件可能不满足 and按电源键关闭屏幕。这种情况下,runloop显然没有什么可处理的,会阻塞。相反,下面的技巧:

// Wait in a run loop
while (processedAlerts != totalToProcess) {
  [NSThread sleepForTimeInterval:0.15];

  // Don't use the following, as it will stop firing in case
  // the runloop has no events (such as touch events) firing
  // [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}

最近 Todoist 的人员发布了一个更新 (11.2.7),表明他们已经解决了 Springboard 崩溃问题。

不久之后,Apple 发布了 iOS 10.2。从那时起,我开始收到我的应用程序用户的报告,说这个错误已经解决了。然而,出于好奇 Todoist 的人是如何解决这个问题的,我联系了他们,这是他们的首席 iOS 开发人员与我分享的内容:

Hi Junjie,

Yes, you’re right. The springboard crash in iOS 10 was actually related to scheduling local user notifications. That issue was actually fixed on iOS 10.2, but we also fixed it for iOS 10.1 by just doing the needed changes to user notifications. Before we was adding all requests, regardless if they was already added, and we started to compare them with the already scheduled and just add those that are different:

let requestsToAdd = requestsToSchedule.filter{!pendingRequests.contains([=10=])}

Hope this helps.

Nuno