我正在 XCode 12.5 中撰寫一個 Swift iOS 應用程式,它可以讓您記錄與聯系人的“事件”(互動)。進行一些更改后,在我的手機上啟動該應用程式時,我幾個月沒有接觸過的應用程式的一部分產生了 EXC_BAD_ACCESS 錯誤 - 一個通知管理器,它根據您對任何聯系人所做的最新筆記創建提醒.
作為背景,我使用 CoreData 將應用程式的資料存盤在聯系人和便箋上,使用 NSManagedObjects 來表示聯系人物件;每個 Contact 物件都有 0 到多個 Event 物件。幾個月前,該應用程式在我的 iPhone 上運行良好,在模擬器上運行良好,因為我最近幾天/幾周一直在更改代碼。我已經嘗試使用 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
}
_錯誤訊息:_執行緒 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 上抓取許多執行緒但無濟于事,希望我只是錯過了一些非常簡單的東西..
uj5u.com熱心網友回復:
將地址消毒劑添加到您的方案中,并在模擬器上運行應用程式。Hopofully sanitizer 會更準確地向您顯示代碼中存在資料競爭的位置。
- 單擊您的方案(在模擬器旁邊)-> 編輯方案
- 選擇診斷并檢查“地址清理程式”
- 在模擬器上運行您的應用程式

uj5u.com熱心網友回復:
堆疊跟蹤中的 NSFaultingMutableSet 指出了從我的核心資料存盤中訪問資料的問題(例如,像 self.events 這樣的事件物件)。我的通知管理器在一個單獨的執行緒上運行并創建了一個不穩定的情況,即同時在主執行緒和輔助執行緒上讀取和修改核心資料(我沒有為多執行緒訪問正確設定)。
我能夠通過將訪問核心資料物件的通知管理器代碼包裝在一個DispatchQueue.main.async {...}塊中來解決這個問題。還有其他方法可以設定 Core Data 物件以從多個執行緒訪問(例如,Coredata - Multithreading best way),但這是最簡單的解決方案,因為多執行緒訪問不是我想要做的事情的優先級。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/412650.html
標籤:
