iosswiftcore-datadatabase-concurrency

Core data Crash: EXC_BAD_ACCESS while trying access data got using predicate


I have save values to entity method which save new data and updates existing data.

func saveSteps(_ serverJson: [[String: Any]]){
   let stepService = StepService(context: context);
   if(serverJson.count > 0){
     for step in serverJson {
       let stepTitle = step["stepTitle"] as? String ?? ""
       let stepDescription = step["stepDescription"] as? String ?? ""
       let stepId = step["_id"] as? String ?? ""
       let predicate: NSPredicate = NSPredicate(format: "stepId=%@", stepId)
       let stepList = stepService.get(withPredicate: predicate);
       if(stepList.count == 0){
         stepService.create(stepId: stepId, stepTitle: stepTitle, stepDescription: stepDescription);
       }else{
         if let updatableStep = stepList.first{
           updatableStep.stepDescription = stepDescription //EXC_BAD_ACCESS Error Here
           updatableStep.stepName = stepName
           updatableStep.stepTitle = stepTitle
           stepService.update(updatedStep: updatableStep)
      }else{
        stepService.create(stepId: stepId, stepTitle: stepTitle, stepDescription: stepDescription);
      }
  }


    saveContext()
}

My Create update and get methods are in stepService

func create(stepId:String, stepDescription: String, stepTitle:String){
   let newItem = NSEntityDescription.insertNewObject(forEntityName: "Steps", into: context) as! Steps //EXC_BAD_ACCESS Error Here
    newItem.stepId = stepId
    newItem.stepTitle = stepTitle
    newItem.stepDescription = stepDescription
}
func update(updatedStep: Steps){
  if let step = getById(id: updatedStep.objectID){
     step.stepId = updatedStep.stepId
     step.stepTitle = updatedStep.stepTitle
     step.stepDescription = updatedStep.stepDescription
}
func get(withPredicate queryPredicate: NSPredicate) -> [Steps]{
 let fetchRequest: NSFetchRequest<Steps> = Steps.fetchRequest()

    fetchRequest.returnsObjectsAsFaults = false
    fetchRequest.predicate = queryPredicate

    do {
        let response = try context.fetch(fetchRequest)
        return response

        } catch let error as NSError {
            // failure
            print(error)
            return [Steps]()
        }
    }
}

Mysave context method is

// Creating private queue to save the data to disk
    lazy var savingModelcontext:NSManagedObjectContext = {
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = self.coordinator

        return managedObjectContext
    }()

    // Creating Context to save in block main queue this will be temporary save
    lazy var context:NSManagedObjectContext = {
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        managedObjectContext.parent = self.savingModelcontext

        return managedObjectContext
    }()

func saveContext () {
    guard savingModelcontext.hasChanges || context.hasChanges else {
        return
    }

    context.performAndWait {
        do {
            try self.context.save()
        } catch let error as NSError {
            print("Could not save in Context: \(error.localizedDescription)")
        }
    }

    savingModelcontext.perform {
        do {
            try self.savingModelcontext.save()
        } catch let error as NSError {
            print("Could not save savingModelContext: \(error.localizedDescription)")
        }
    }
}

There are two places that core data crashes with same error message one is when i access the data to update the method and other is when i am trying to create a new item using NSEntityDescription.insertNewObject with entity name. while saing i have tried Dispach queue with qos of userInitiated and default. I didn't use background as user might open some thing that might use this.

The problem is the crash is not consistanct and has never crashed when doing a debug which leads me to belive it is concurrency issue but the data is never deleted or read when being updated.

PS: I have read the questions with same and similar issues but i could not get a working answer here the question.

Kidly point out if i have made any mistakes

Thanks any help is appreciated


Solution

  • The Reason fo the crash was i was trying to change was that i was using and using private queue context in main thread and vise versa. to fix this using Group Dispach queue with desired QOS for private queue context and main thread for using main queue objects.