代码之家  ›  专栏  ›  技术社区  ›  Samarth Kejriwal

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

  •  0
  • Samarth Kejriwal  · 技术社区  · 5 年前

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

    问题是我可以在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
            }
        }
    }
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Caleb    5 年前

    因此,为了线程安全,我在多个线程上使用核心数据

    你这是什么意思?使用多个线程并不能保证任何线程安全。线程安全与在多个线程上运行代码而不出现问题的能力有关,它通常要求您采取一些预防措施以防止线程相互干扰。

    问题是,我可以在CoreData中插入数据,但从CoreData中提取数据时,结果为零,这是在我关闭应用程序并从数据库中提取数据时发生的。这与NSMangedObjectContext有关,但我无法理解。

    您需要理解什么是托管对象上下文。把它想象成一个临时工作区:您可以执行一个获取请求,将对象从持久性存储带到托管对象上下文中,您可以向上下文中添加新对象,并且可以在上下文中操作对象。在将上下文保存回持久存储之前,在上下文中所做的更改并不意味着上下文之外的任何内容。

    您可能没有看到正在添加的对象的几个原因是:

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

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

    • 保存添加对象的上下文,但从未保存父上下文(托管对象上下文是分层的)。

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

    • 在多个线程中使用同一个上下文,而没有注意序列化上下文上的操作(也就是说,您的代码) 不是吗 线程安全)。

    要想弄明白这一点,你真正应该做的是让自己回到一种可以可靠地存储和检索对象的状态。尝试只使用一个线程,确保操作正常。如果他们不这样做,首先解决这个问题。接下来,深入了解托管对象上下文如何工作以及如何使用它们。最后,请仔细阅读 concurrency and Core Data .

        2
  •  1
  •   Shubham Bakshi    5 年前

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

    你已经准备好了 privateManagedObjectContext 的父母 managedContext ,但你没有储蓄 managedContext

    打完电话 privateManagedObjectContext.save() ,你需要打电话 managedContext.save()