即使在 Core Data 上下文保存后数据也没有保留
Posted
技术标签:
【中文标题】即使在 Core Data 上下文保存后数据也没有保留【英文标题】:Data not persisted even after Core Data context save 【发布时间】:2017-07-21 09:03:52 【问题描述】:我在核心数据的持久性方面遇到了一些问题。 我正在使用 NSSQLiteStoreType persistentStore(见下文)。 在我的应用程序中,每次我修改、创建或删除一些数据时,我都会通过调用 saveContext() 上面的函数立即将这些更改保存在我的核心数据中
但是,有时这些更改不会持续存在! (这个不持久的问题并不总是出现,我还是没有成功重现这个bug)
这是这些数据之一的生命周期:
用户修改 保存上下文(patient.managedObjectContext,其中患者是链接到所有其他数据实体的主要实体) 使用 AlamoFire 与后端同步 收到后端应答后在数据中设置远程ID 再次保存上下文(仍在 Alamofire 完成处理程序中:在主线程中执行,通过打印 Thread.current 进行检查)最后,当这个错误发生时,它不仅影响一个数据,而且似乎影响从当前会话(从上次打开到关闭)修改和保存的所有数据
这是我的 coredatacontroller 的代码:
class CoreDataController: NSObject
static let shared = CoreDataController()
var managedObjectContext: NSManagedObjectContext
override init()
// This resource is the same name as your xcdatamodeld contained in your project.
guard let modelURL = Bundle.main.url(forResource: "xxx", withExtension:"momd") else
fatalError("Error loading model from bundle")
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
guard let mom = NSManagedObjectModel(contentsOf: modelURL) else
fatalError("Error initializing mom from: \(modelURL)")
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
let options = [ NSInferMappingModelAutomaticallyOption : true,
NSMigratePersistentStoresAutomaticallyOption : true]
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = psc
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docURL = urls[urls.endIndex-1]
/* The directory the application uses to store the Core Data store file.
This code uses a file named "DataModel.sqlite" in the application's documents directory.
*/
let storeURL = docURL.appendingPathComponent("xxx.sqlite")
do
try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)
catch let error
fatalError("Error migrating store: \(error)")
这里是我的 coredatacontroller 实例化的地方:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
let coreDataController : CoreDataController = CoreDataController.shared
// FIXME: determiner le comportement attendu pour le badge sur l'icone et l'appliquer !!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
guard let window = window else
fatalError("Pas de window !!!")
......
这是我每次想在我的 coreData 中保存数据时使用的函数:
extension NSManagedObjectContext
func saveContext()
do
try self.save()
catch let error
print("Failure to save context: \(error)")
希望这个问题能启发你,并提前感谢你的想法!
编辑 1:
经过进一步调查,我所有的同步过程(包括 alamofire 请求)都在主线程中完成(我通过打印 Thread.current 检查了每一步)。
编号 = 1,名称 = 主要 dataFromJson 线程 编号 = 1,名称 = 主要 冲突处理者的线程 编号 = 1,名称 = 主要 fetchDataToSync 线程 编号 = 1,名称 = 主要此外,在检查了我的后端数据库和我的 coredata 之间的差异之后,似乎 coredata 无法保存所有数据,直到应用程序崩溃(自愿或非自愿)然后重新启动应用程序,这将“重新启动”我的 coredata控制器。
【问题讨论】:
【参考方案1】:很难确定,但有一个细节组合会带来麻烦,可能是导致此问题的原因。你提到
再次保存上下文(仍在 Alamofire 的线程中)
查看代码我看到了:
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
后来是这样的:
do
try self.save()
catch let error
print("Failure to save context: \(error)")
因此,您有一个使用主队列并发的上下文,但是您只需调用save()
就可以保存主线程之外的更改。这不好。 Core Data 不是线程安全的,而且你正在跨线程。
要解决此问题,您确实需要在托管上下文中使用 perform
或 performAndWait
方法,只要您在主线程之外使用它。这包括所有访问,可能以任何方式触及上下文的所有内容——获取请求、访问托管对象的属性或关系以及保存更改。这就是 Core Data 想要处理线程的方式。
【讨论】:
感谢您的建议!经过进一步调查,我所有的同步过程(包括 alamofire 请求)都在主线程中完成(我通过打印 Thread.current 检查了每一步)。此外,在检查了我的后端数据库和我的 coredata 之间的差异之后,似乎 coredata 无法保存所有数据,直到应用程序崩溃(自愿或非自愿)然后重新启动将“重新启动”我的 coredata 控制器的应用程序。 今天我解决了这个问题,你对它的来源是对的。一个回调试图访问 coredata nd 是造成这些错误的原因! 你好,保罗,我能告诉我更多你发现了什么吗?我正在努力解决同样的问题。所以没有崩溃,只是有时核心数据中的数据丢失,我无法重现它。应用程序崩溃了吗?还是只是无法保存数据(所以您丢失了一些数据?)以上是关于即使在 Core Data 上下文保存后数据也没有保留的主要内容,如果未能解决你的问题,请参考以下文章
iPhone Core Data 一次保存多个项目的随机行为?