核心数据错误-非常随机

时间:2018-06-30 19:01:27

标签: ios swift runtime-error

我知道该帖子也有其他类似的帖子,但是到目前为止,我所发现的任何信息都无法解决我的问题。我通过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)
    }
}

0 个答案:

没有答案