在 Swift iOS App 启动时查找 EXC_BAD_ACCESS Code=1 的原因
Finding the cause of EXC_BAD_ACCESS Code=1 on startup of Swift iOS App
我正在 XCode 12.5 中编写一个 Swift iOS 应用程序,让您可以记录与联系人的“事件”(交互)。进行一些更改后,在我的 phone 上启动该应用程序时,应用程序的一部分出现了 EXC_BAD_ACCESS 错误,我已经几个月没有碰过它了——通知管理器会根据您最近的笔记创建提醒接管了您的任何联系人。
作为背景,我使用 CoreData 来存储应用程序的联系人和笔记数据,使用 NSManagedObjects 来表示联系人对象;每个 Contact 对象都有 0 到多个 Event 对象。几个月前,该应用程序在我的 iPhone 上运行良好,在模拟器上运行良好,因为我最近 days/weeks 一直在更改代码。我已经尝试使用 Instruments 工具来检查 Zombies 和 Leaks,但结果空手而归。我还尝试评估导致错误访问错误的代码行上的变量,但找不到问题。
概括地说,这是导致问题的执行顺序:
- 应用从 Core Data 加载对象上下文
- 通知管理器检查应用程序是否已获得通知授权
- 如果是,闭包调用方法添加提醒
- 在 addReminder() 中,它调用 getEvents(...)(见下文)
- getEvents 在循环遍历每个联系人并尝试访问每个联系人的“事件”(NSManagedObject)时引发 EXC_BAD_ACCESS 错误。我尝试进行更改以隔离与联系人或事件相关的任何问题,但这些变量似乎填充了合理的数据(例如,联系人可能有正确的名称或联系人的事件列表可能为空)
func getEvents(last90days: Bool = false) -> [Event] {
var events = [Event]()
let keyDate = Date(timeIntervalSinceNow: -90 * 60 * 60 * 24)
for case let event as Event in (self.events ?? []) { // this is the line where the EXC_BAD_ACCESS occurs. Even if I nil-coalesce above this line separately, the problem still persists.
if last90days && event.timestamp != nil {
if event.timestamp == nil {
continue
}
if event.timestamp! < keyDate {
continue
}
}
events.append(event)
}
return events
}
_Error Message:_Thread 4:EXC_BAD_ACCESS(代码=1,地址=0x1fa9bf0)
堆栈跟踪:
* thread #4, queue = 'com.apple.usernotifications.UNUserNotificationServiceConnection.call-out', stop reason = EXC_BAD_ACCESS (code=1, address=0x1fa9bf0)
frame #0: 0x00000001ace04334 libobjc.A.dylib`object_getMethodImplementation + 48
frame #1: 0x00000001982d7c04 CoreFoundation`_NSIsNSSet + 40
frame #2: 0x00000001981aaf18 CoreFoundation`-[NSMutableSet unionSet:] + 108
frame #3: 0x000000019e3c93b0 CoreData`-[_NSFaultingMutableSet willReadWithContents:] + 636
frame #4: 0x000000019e3e7ff4 CoreData`-[_NSFaultingMutableSet countByEnumeratingWithState:objects:count:] + 48
frame #5: 0x000000019bd12bd0 libswiftFoundation.dylib`Foundation.NSFastEnumerationIterator.next() -> Swift.Optional<Any> + 180
* frame #6: 0x0000000100dbb03c myApp`Contact.getEvents(last90days=false, self=0x0000000281b32f80) at Contact+helpers.swift:48:9
frame #7: 0x0000000100db7bc8 myApp`InteractionAnalyzer.countInteractions(startDate=2022-01-03 04:12:17 UTC, endDate=2022-01-10 04:12:17 UTC, name=nil, onlyIncludeNewSparks=false, excludeNewSparks=false, sparkStartDate=nil, self=0x00000002838feb20) at InteractionAnalyzer.swift:24:48
frame #8: 0x0000000100dfac18 myApp`NotificationManager.getNotificationString(self=0x000000028377a220) at NotificationManager.swift:74:60
frame #9: 0x0000000100dfa368 myApp`NotificationManager.addNotificationRequest(self=0x000000028377a220) at NotificationManager.swift:62:29
frame #10: 0x0000000100df9ab8 myApp`closure #1 in NotificationManager.addReminder(settings=0x0000000281355490, self=0x000000028377a220) at NotificationManager.swift:36:22
frame #11: 0x0000000100df98d4 myApp`thunk for @escaping @callee_guaranteed (@guaranteed UNNotificationSettings) -> () at <compiler-generated>:0
frame #12: 0x000000010146c0b4 libdispatch.dylib`_dispatch_call_block_and_release + 32
frame #13: 0x000000010146dde0 libdispatch.dylib`_dispatch_client_callout + 20
frame #14: 0x0000000101475ef0 libdispatch.dylib`_dispatch_lane_serial_drain + 788
frame #15: 0x0000000101476d48 libdispatch.dylib`_dispatch_lane_invoke + 496
frame #16: 0x0000000101483a50 libdispatch.dylib`_dispatch_workloop_worker_thread + 1600
frame #17: 0x00000001e3f927a4 libsystem_pthread.dylib`_pthread_wqthread + 276
我怎样才能查明这个原因?我已经在 EXC_BAD_ACCESS 上抓取了很多主题但都无济于事,我希望我只是遗漏了一些非常简单的东西..
将地址清理程序添加到您的方案中,并在模拟器上运行 应用程序。 Hopofully sanitizer 将更准确地向您显示代码中存在数据竞争的位置。
- 单击您的方案(在模拟器旁边)-> 编辑方案
- Select 诊断并检查“地址消毒器”
- 运行 您在模拟器上的应用程序
堆栈跟踪中的 NSFaultingMutableSet 指出了从我的核心数据存储访问数据的问题(例如,像 self.events 这样的事件对象)。我的通知管理器在单独的线程上运行并造成不稳定的情况,其中核心数据(我没有为多线程访问正确设置)在主线程和辅助线程上同时读取和修改。
我能够通过将访问核心数据对象的通知管理器代码包装在 DispatchQueue.main.async {...}
块中来解决问题。还有其他方法可以设置 Core Data 对象以从多个线程访问(例如,),但这是最简单的解决方案,因为多线程访问不是我正在尝试做的优先事项。
我正在 XCode 12.5 中编写一个 Swift iOS 应用程序,让您可以记录与联系人的“事件”(交互)。进行一些更改后,在我的 phone 上启动该应用程序时,应用程序的一部分出现了 EXC_BAD_ACCESS 错误,我已经几个月没有碰过它了——通知管理器会根据您最近的笔记创建提醒接管了您的任何联系人。
作为背景,我使用 CoreData 来存储应用程序的联系人和笔记数据,使用 NSManagedObjects 来表示联系人对象;每个 Contact 对象都有 0 到多个 Event 对象。几个月前,该应用程序在我的 iPhone 上运行良好,在模拟器上运行良好,因为我最近 days/weeks 一直在更改代码。我已经尝试使用 Instruments 工具来检查 Zombies 和 Leaks,但结果空手而归。我还尝试评估导致错误访问错误的代码行上的变量,但找不到问题。
概括地说,这是导致问题的执行顺序:
- 应用从 Core Data 加载对象上下文
- 通知管理器检查应用程序是否已获得通知授权
- 如果是,闭包调用方法添加提醒
- 在 addReminder() 中,它调用 getEvents(...)(见下文)
- getEvents 在循环遍历每个联系人并尝试访问每个联系人的“事件”(NSManagedObject)时引发 EXC_BAD_ACCESS 错误。我尝试进行更改以隔离与联系人或事件相关的任何问题,但这些变量似乎填充了合理的数据(例如,联系人可能有正确的名称或联系人的事件列表可能为空)
func getEvents(last90days: Bool = false) -> [Event] {
var events = [Event]()
let keyDate = Date(timeIntervalSinceNow: -90 * 60 * 60 * 24)
for case let event as Event in (self.events ?? []) { // this is the line where the EXC_BAD_ACCESS occurs. Even if I nil-coalesce above this line separately, the problem still persists.
if last90days && event.timestamp != nil {
if event.timestamp == nil {
continue
}
if event.timestamp! < keyDate {
continue
}
}
events.append(event)
}
return events
}
_Error Message:_Thread 4:EXC_BAD_ACCESS(代码=1,地址=0x1fa9bf0) 堆栈跟踪:
* thread #4, queue = 'com.apple.usernotifications.UNUserNotificationServiceConnection.call-out', stop reason = EXC_BAD_ACCESS (code=1, address=0x1fa9bf0)
frame #0: 0x00000001ace04334 libobjc.A.dylib`object_getMethodImplementation + 48
frame #1: 0x00000001982d7c04 CoreFoundation`_NSIsNSSet + 40
frame #2: 0x00000001981aaf18 CoreFoundation`-[NSMutableSet unionSet:] + 108
frame #3: 0x000000019e3c93b0 CoreData`-[_NSFaultingMutableSet willReadWithContents:] + 636
frame #4: 0x000000019e3e7ff4 CoreData`-[_NSFaultingMutableSet countByEnumeratingWithState:objects:count:] + 48
frame #5: 0x000000019bd12bd0 libswiftFoundation.dylib`Foundation.NSFastEnumerationIterator.next() -> Swift.Optional<Any> + 180
* frame #6: 0x0000000100dbb03c myApp`Contact.getEvents(last90days=false, self=0x0000000281b32f80) at Contact+helpers.swift:48:9
frame #7: 0x0000000100db7bc8 myApp`InteractionAnalyzer.countInteractions(startDate=2022-01-03 04:12:17 UTC, endDate=2022-01-10 04:12:17 UTC, name=nil, onlyIncludeNewSparks=false, excludeNewSparks=false, sparkStartDate=nil, self=0x00000002838feb20) at InteractionAnalyzer.swift:24:48
frame #8: 0x0000000100dfac18 myApp`NotificationManager.getNotificationString(self=0x000000028377a220) at NotificationManager.swift:74:60
frame #9: 0x0000000100dfa368 myApp`NotificationManager.addNotificationRequest(self=0x000000028377a220) at NotificationManager.swift:62:29
frame #10: 0x0000000100df9ab8 myApp`closure #1 in NotificationManager.addReminder(settings=0x0000000281355490, self=0x000000028377a220) at NotificationManager.swift:36:22
frame #11: 0x0000000100df98d4 myApp`thunk for @escaping @callee_guaranteed (@guaranteed UNNotificationSettings) -> () at <compiler-generated>:0
frame #12: 0x000000010146c0b4 libdispatch.dylib`_dispatch_call_block_and_release + 32
frame #13: 0x000000010146dde0 libdispatch.dylib`_dispatch_client_callout + 20
frame #14: 0x0000000101475ef0 libdispatch.dylib`_dispatch_lane_serial_drain + 788
frame #15: 0x0000000101476d48 libdispatch.dylib`_dispatch_lane_invoke + 496
frame #16: 0x0000000101483a50 libdispatch.dylib`_dispatch_workloop_worker_thread + 1600
frame #17: 0x00000001e3f927a4 libsystem_pthread.dylib`_pthread_wqthread + 276
我怎样才能查明这个原因?我已经在 EXC_BAD_ACCESS 上抓取了很多主题但都无济于事,我希望我只是遗漏了一些非常简单的东西..
将地址清理程序添加到您的方案中,并在模拟器上运行 应用程序。 Hopofully sanitizer 将更准确地向您显示代码中存在数据竞争的位置。
- 单击您的方案(在模拟器旁边)-> 编辑方案
- Select 诊断并检查“地址消毒器”
- 运行 您在模拟器上的应用程序
堆栈跟踪中的 NSFaultingMutableSet 指出了从我的核心数据存储访问数据的问题(例如,像 self.events 这样的事件对象)。我的通知管理器在单独的线程上运行并造成不稳定的情况,其中核心数据(我没有为多线程访问正确设置)在主线程和辅助线程上同时读取和修改。
我能够通过将访问核心数据对象的通知管理器代码包装在 DispatchQueue.main.async {...}
块中来解决问题。还有其他方法可以设置 Core Data 对象以从多个线程访问(例如,