I have an NSFetchedResultsController and I am trying to update my data on a background context. For example, here I am trying to delete an object:
This works me perfectly in my project. In function updateEnglishNewsListener(:), here parameter data is in anyobject and i further convert it into json formate for saving purpose.
Core Data uses thread (or serialized queue) confinement to protect managed objects and managed object contexts (see Core Data Programming Guide). A consequence of this is that a context assumes the default owner is the thread or queue that allocated it—this is determined by the thread that calls its init method. You should not, therefore, initialize a context on one thread then pass it to a different thread.
There are three type 1. ConfinementConcurrencyType 2. PrivateQueueConcurrencyType 3. MainQueueConcurrencyType
The MainQueueConcurrencyType creates a context associated with the main queue which is perfect for use with NSFetchedResultsController.
In updateEnglishNewsListener(:) function, params data is your input. (data->Data you wants to update.)
private func updateEnglishNewsListener(data: [AnyObject] ){
//Here is your data
let privateAsyncMOC_En = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
// The context is associated with the main queue, and as such is tied into the application’s event loop, but it is otherwise similar to a private queue-based context. You use this queue type for contexts linked to controllers and UI objects that are required to be used only on the main thread.
privateAsyncMOC_En.parent = managedObjectContext
privateAsyncMOC_En.perform{
// The perform(_:) method returns immediately and the context executes the block methods on its own thread. Here it use background thread.
let convetedJSonData = self.convertAnyobjectToJSON(anyObject: data as AnyObject)
for (_ ,object) in convetedJSonData{
self.checkIFNewsIdForEnglishAlreadyExists(newsId: object["news_id"].intValue, completion: { (count) in
if count != 0{
self.updateDataBaseOfEnglishNews(json: object, newsId: object["news_id"].intValue)
}
})
}
do {
if privateAsyncMOC_En.hasChanges{
try privateAsyncMOC_En.save()
}
if managedObjectContext.hasChanges{
try managedObjectContext.save()
}
}catch {
print(error)
}
}
}
Checking data is already exist in coredata or not for avoiding the redundance data. Coredata have not primary key concept so we sequently check data already exist in coredata or not. Data is updated if and only if updating data is already exist in coredata. Here checkIFNewsIdForEnglishAlreadyExists(:) function return 0 or value . If it returns 0 then data is not saved in database else saved. I am using completion handle for knowing the new data or old data.
private func checkIFNewsIdForEnglishAlreadyExists(newsId:Int,completion:(_ count:Int)->()){
let fetchReq:NSFetchRequest = TestEntity.fetchRequest()
fetchReq.predicate = NSPredicate(format: "news_id = %d",newsId)
fetchReq.fetchLimit = 1 // this gives one data at a time for checking coming data to saved data
do {
let count = try managedObjectContext.count(for: fetchReq)
completion(count)
}catch{
let error = error as NSError
print("\(error)")
completion(0)
}
}
Replacing the old data to new one according to requirement.
private func updateDataBaseOfEnglishNews(json: JSON, newsId : Int){
do {
let fetchRequest:NSFetchRequest = TestEntity.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "news_id = %d",newsId)
let fetchResults = try managedObjectContext.fetch(fetchRequest as! NSFetchRequest) as? [TestEntity]
if let fetchResults = fetchResults {
if fetchResults.count != 0{
let newManagedObject = fetchResults[0]
newManagedObject.setValue(json["category_name"].stringValue, forKey: "category_name")
newManagedObject.setValue(json["description"].stringValue, forKey: "description1")
do {
if ((newManagedObject.managedObjectContext?.hasChanges) != nil){
try newManagedObject.managedObjectContext?.save()
}
} catch {
let saveError = error as NSError
print(saveError)
}
}
}
} catch {
let saveError = error as NSError
print(saveError)
}
}
Convertion anyobject to JSON for saving purpose in coredata
func convertAnyobjectToJSON(anyObject: AnyObject) -> JSON{
let jsonData = try! JSONSerialization.data(withJSONObject: anyObject, options: JSONSerialization.WritingOptions.prettyPrinted)
let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String
if let dataFromString = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: false) {
let json = JSON(data: dataFromString)
return json
}
return nil
}
Hope it will help you. If any confusion then please ask.