多线程上的核心数据操作导致插入但没有获取

Core Data operations on multiple thread causing insertion but no fetching

我正在使用 CoreData 来插入数据和获取数据,因为我有很多数据,所以我在多个线程上使用核心数据以保证线程安全。

问题是我可以在 CoreData 中插入数据,但是从 CoreData 中获取数据时,结果为零,当我终止我的应用程序并从数据库中获取数据时会发生这种情况。这与 NSMangedObjectContext 有关,但我无法弄清楚。

这是我的代码片段:

class CoreDataManager {

    static let sharedManager = CoreDataManager()
    private init() {}

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "My_Contacts")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    func saveContext() {
        let context = CoreDataManager.sharedManager.persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

    func insertContact(id:Int, firstName : String,lastName : String,emaild : String,isFavorite : Bool,phoneNum : String,profilePic : String,sync : Bool) -> Contact? {
        let managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
        let privateManagedObjectContext: NSManagedObjectContext = {
            //NSPrivateQueueConcurrencyType
            let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
            moc.parent = managedContext
            return moc
        }()


        let entity = NSEntityDescription.entity(forEntityName: "Contact",
                                                in: privateManagedObjectContext)!
        let contact = NSManagedObject(entity: entity,
                                     insertInto: privateManagedObjectContext)
        contact.setValue(firstName, forKey: "first_name")
        contact.setValue(lastName, forKey: "last_name")
        contact.setValue(emaild, forKey: "email")
        contact.setValue(isFavorite, forKey: "favorite")
        contact.setValue(phoneNum, forKey: "phone_number")
        contact.setValue(profilePic, forKey: "profile_pic")
        contact.setValue(sync, forKey: "syncStatus")
        contact.setValue(id, forKey: "contactId")

        do {
            try privateManagedObjectContext.save()
            return contact as? Contact
        } catch let error as NSError {
            print("Could not save. \(error), \(error.userInfo)")
            return nil
        }
    }


    func fetchAllContacts() -> [Contact]?{

        let managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Contact")

        do {
            let people = try managedContext.fetch(fetchRequest)
            return people as? [Contact]
        } catch let error as NSError {
            print("Could not fetch. \(error), \(error.userInfo)")
            return nil
        }
    }
}

由于您正在使用多个 MOC(托管对象上下文),因此您需要保存两个上下文

您已将 privateManagedObjectContext 的父项设置为 managedContext,但您并未保存 managedContext

调用privateManagedObjectContext.save()后,还需要调用managedContext.save()

so I am using core data on multiple threads in order to be thread-safe

你这是什么意思?使用多线程不会产生任何结果 thread-safe。线程安全与您 运行 在多个线程上毫无问题地编写代码的能力有关,它通常要求您采取一些预防措施来防止线程相互干扰。

The problem is that I am able to insert Data in CoreData, but while fetching from CoreData, the results are zero, this is happening when I kill my app and fetch the data from Database. This has something to do with NSMangedObjectContext but I am not able to figure it out.

您需要了解什么是托管对象上下文。将其视为一个临时工作区:您可以执行获取请求以将对象从持久存储带入托管对象上下文,您可以将新对象添加到上下文,并且可以在上下文中操作对象。在将上下文保存回持久存储之前,您在上下文中所做的更改在上下文之外没有任何意义。

您可能看不到要添加的对象的几个原因是:

  • 您正在添加对象并尝试在不同的上下文中读回它们。

  • 添加对象后永远不会保存上下文。

  • 您保存了添加对象的上下文,但永远不会保存父上下文(托管对象上下文是分层的)。

  • 您尝试在添加对象后保存上下文,但保存失败。

  • 您在多个线程中使用相同的上下文,而没有注意序列化上下文中的操作(也就是说,您的代码不是 thread-safe).

要解决这个问题,您真正应该做的是让自己回到可以可靠地存储和检索对象的状态。尝试只使用一个线程并确保您的操作有效。如果他们不这样做,请先修复它。接下来,深入了解托管对象上下文的工作原理和使用方法。最后,继续阅读 concurrency and Core Data