我知道该帖子也有其他类似的帖子,但是到目前为止,我所发现的任何信息都无法解决我的问题。我通过JSON从API接收数据并将其保存,然后在保存之后通过Core Data检索将数据显示到UI。大约每100次左右的搜索(API调用)就会发生这种情况。 1到100之间的数字是随机的。有时是每20次搜索,等等。该应用程序的较新版本似乎更多地存在此问题。
Exception was caught during Core Data change processing. This is
usually a bug within an observer of
NSManagedObjectContextObjectsDidChangeNotification. *** Collection
<__NSCFSet: 0x6000030e7f60> was mutated while being enumerated. with
userInfo (null)
CoreData: error: Serious application error. Exception was caught during
Core Data change processing. This is usually a bug within an observer
of NSManagedObjectContextObjectsDidChangeNotification. *** Collection
<__NSCFSet: 0x6000030e7f60> was mutated while being enumerated. with
userInfo (null)
2018-06-30 12:51:36.264733-0600 [7055:6252340] ***
Terminating app due to uncaught exception 'NSGenericException', reason:
'*** Collection <__NSCFSet: 0x6000030e7f60> was mutated while being
enumerated.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010d829f66 __exceptionPreprocess + 294
1 libobjc.A.dylib 0x000000010c8f904d objc_exception_throw + 48
2 CoreFoundation 0x000000010d826c6c __NSFastEnumerationMutationHandler + 124
3 CoreData 0x000000010d1baf28 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processDeletedObjects:] + 328
4 CoreData 0x000000010d1a529d -[NSManagedObjectContext(_NSInternalChangeProcessing) _propagatePendingDeletesAtEndOfEvent:] + 109
5 CoreData 0x000000010d1a028a -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 1034
6 CoreData 0x000000010d1790ff _performRunLoopAction + 335
7 CoreFoundation 0x000000010d78cea7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
8 CoreFoundation 0x000000010d7872de __CFRunLoopDoObservers + 430
9 CoreFoundation 0x000000010d787981 __CFRunLoopRun + 1553
10 CoreFoundation 0x000000010d787031 CFRunLoopRunSpecific + 625
11 GraphicsServices 0x0000000110d35136 GSEventRunModal + 62
12 UIKitCore 0x0000000116098839 UIApplicationMain + 140
13 AppNameHere 0x00000001063c7234 main + 68
14 libdyld.dylib 0x000000010eed2a61 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
2018-06-30 12:51:36.271149-0600 [7055:6255838] [Assert]
Cannot be called with asCopy = NO on non-main thread.
发布了一些简化的代码(为了便于阅读,删除了一些不专门针对CoreData的内容。我已经知道很多代码都是不好的形式,但这是我的最佳工作,正在努力。
//globalVariable declared:
let appDelegate = UIApplication.shared.delegate as? AppDelegate
//in AppDelegate:
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "AppName")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
//in VC:
let downloadAirports = DownloadAirports()
let initialAirportDownload = defaults.bool(forKey: "initialAirportDownload")
if initialAirportDownload == false {
self.showAirportDownloadingAlert(show: true)
self.downloadAirports.getAirports(completion: {
DispatchQueue.main.async {
print("finishedDownloadingAirports")
self.defaults.set(true, forKey: "initialAirportDownload")
self.showAirportDownloadingAlert(show: false)
})
}
}
//in DownloadAirports class:
struct AirportsJSON : Decodable {
let airports : [AirportJSON]
}
struct AirportJSON : Decodable {
let iata : String?
let airportName : String?
let countryCode : String?
let utcOffset : Int?
let classification : Int?
}
func getAirports(completion: @escaping () -> ()) {
let serverAddress = ServerAccess.serverAddress
let jsonUrlString = "\(serverAddress)"
guard let url = URL(string: jsonUrlString) else {
return
}
deleteAirports()
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {
return
}
do {
let airports = try JSONDecoder().decode(AirportsJSON.self, from: data)
guard let moc = appDelegate?.persistentContainer.viewContext else {
return
}
var i = 0
while i < airports.airports.count {
self.saveAirport(airports: airports.airports[i], moc: moc)
i += 1
}
} catch let jsonErr {
print(jsonErr)
}
completion()
}.resume()
guard let moc = appDelegate?.persistentContainer.viewContext else {
return
}
do {
try moc.save()
} catch {
debugPrint(error.localizedDescription)
}
}
func saveAirport(airports : AirportJSON, moc : NSManagedObjectContext) {
var searchString = ""
let airport = Airports(context: moc)
if let iata = airports.iata {
if let name = airports.airportName {
searchString = "\(iata) - \(name)"
airport.searchString = searchString
airport.iata = iata
print(iata)
}
}
if let classification = airports.classification {
airport.classification = Int16(classification)
}
if let timeZone = airports.utcOffset {
airport.timeZone = Int16(timeZone)
}
if let countryCode = airports.countryCode {
airport.countryCode = countryCode
}
}
func deleteAirports() {
guard let moc = appDelegate?.persistentContainer.viewContext else {
return
}
let fetchRequest : NSFetchRequest<Airports> = Airports.fetchRequest()
do {
let airports = try moc.fetch(fetchRequest)
for airport in airports {
moc.delete(airport)
}
do {
try moc.save()
} catch {
print(error.localizedDescription)
}
} catch {
print(error)
}
}