Samarth Kejriwal
Samarth Kejriwal

Reputation: 1176

Core Data operations on multiple thread causing insertion but no fetching

I am using CoreData to insert data and fetch Data, as I have a lot of data, so I am using core data on multiple threads in order to be 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.

Here is my code snippet :

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
        }
    }
}

Upvotes: 0

Views: 1533

Answers (2)

Caleb
Caleb

Reputation: 125037

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

What do you mean by this? Using multiple threads doesn't make anything thread-safe. Thread safety relates to your ability to run your code on multiple threads without problems, and it generally requires that you take a number of precautions to prevent threads from interfering with each other.

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.

You need to understand what a managed object context is. Think of it like a temporary workspace: you can execute a fetch request to bring objects from a persistent store into a managed object context, and you can add new objects to the context, and you can manipulate the objects in a context. The changes you make in a context don't mean anything outside the context until you save the context back to the persistent store.

A few reasons you might not be seeing the objects you're adding are:

  • You're adding the objects and trying to read them back in different contexts.

  • You never save the context after you add objects.

  • You save the context in which you added the object, but the parent context (managed object contexts are hierarchical) is never saved.

  • You try to save the context after you add objects, but saving fails.

  • You're using the same context in multiple threads without taking care to serialize the operations on the context (which is to say, your code isn't thread-safe).

What you really should do to figure this out is to get yourself back to a state where you can store and retrieve objects reliably. Try using just one thread and make sure that your operations work. If they don't, fix that first. Next, get a solid understanding of how managed object contexts work and how to use them. Finally, read up on concurrency and Core Data.

Upvotes: 2

Shubham Bakshi
Shubham Bakshi

Reputation: 572

Since you are using multiple MOC(Managed Object Context), you need to save both the contexts

You have set privateManagedObjectContext's parent to managedContext, but you are not saving managedContext

After calling privateManagedObjectContext.save(), you need to call managedContext.save() as well

Upvotes: 1

Related Questions