我知道并发真的很头疼。我读了很多关于如何解析和保存服务器数据到核心数据的文章。但很多教程都非常基础,不适用于线程。但是当我们开发应用程序时,需要多线程。
我的应用程序流程如下
1.使用URLSession从服务器获取数据
2.解析
3.保存核心数据 - 在后台,需要检查重复数据
4.然后获取数据
5.更新UI。
陷入第3步保存到核心数据 - 在后台,需要检查重复
我看到,URLSession正在后台线程中运行。苹果说需要使用performblock吗?https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html
我尝试了以下方式。但有时它会崩溃。任何人都建议正确的编程流程会更好。有很多问题但是对于这个问题没有正确的解决方案。
func DownloadFrom_server(dict:Any,urlstring_get:String) {
if JSONSerialization.isValidJSONObject(dict) {
do{
let json:Data = try JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions.prettyPrinted)
var urlString = urlstring_get
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPathAllowed)!
var httpRequest = URLRequest(url: URL(string: urlString)!)
httpRequest.httpMethod = "POST"
httpRequest.httpBody = json
let sessionConfig = URLSessionConfiguration.default
sessionConfig.httpAdditionalHeaders = ["Accept" : "application/json", "api-key" : "API_KEY"]
let session = URLSession(configuration: sessionConfig)
let task = session.dataTask(with: httpRequest) { data, response, error in
guard let data_get = data, error == nil else{// check for fundamental networking error
print("data nil\(error)")
//1.network connection lost
//save offline data
return
}
do {
let jsonResult = try JSONSerialization.jsonObject(with: data_get, options: JSONSerialization.ReadingOptions.mutableContainers)
print("cloud data",jsonResult)
self.Save_server_Data_ToCoreData(jsonResult: jsonResult)
}
catch {
print("json result parsing error ",error)
}
}
task.resume()
}
catch{
print("InValidJSONObject json:Data error - ",error)
}
}
}
将服务器josn保存到核心数据,如下所示
func Save_server_Data_ToCoreData(jsonResult:Any) {
let context = getContext()
let privateMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateMOC.parent = context
privateMOC.perform {
if let data = jsonResult as? [[String: AnyObject]]{
//Heree prepare MOC
// if i need to check data alredy exits or not means how can i check
}
do {
try privateMOC.save()
context.performAndWait {
do {
try context.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
} catch {
fatalError("Failure to save context: \(error)")
}
}
DispatchQueue.main.async(execute: {
print("update main")
})
}
我想再按照以下方式做事
DispatchQueue.global(qos: .background).async {
//saving core data
//fetching data
DispatchQueue.main.async {
//update UI
}
}
不确定需要使用哪个上下文,私有或主要。如果任何回答这个问题的人对像我这样的Multithread中的那么多初学者都有用。
答案 0 :(得分:1)
用于核心数据的重复检查。在ios9之上,Coredata中有一个独特的约束功能。
在实体描述的约束中设置属性名称,如id,name等
并在managedobjectcontext中将合并策略设置为NSMergeByPropertyObjectTrumpMergePolicy
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
请记住,如果您的实体中有关系(我已在xcode7.3中查看),则上述欺骗性检查功能不起作用。
答案 1 :(得分:0)
您可以使用id
等唯一字段检查或创建新功能的功能。如果说记录已经存在,则可以跳过或更新字段,但不能创建新记录。 (确保您的实体具有主键的唯一字段)
您可以在循环从服务器API
收到的数据时调用此方法func findOrCreate(byId objectId: String) -> NSManagedObject {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Document")
// Create a new predicate that filters out any object that equal to this id
print("looking for id: \(objectId)")
let predicate = NSPredicate(format: "objectId == %@", objectId)
// Set the predicate on the fetch request
fetchRequest.predicate = predicate
do {
// if found in core data
let results = try managedObjectContext.fetch(fetchRequest)
if !results.isEmpty {
return results.first as! NSManagedObject
}
} catch let error as NSError {
print("Could not create object \(error), \(error.userInfo)")
}
// else create new object
let entity = NSEntityDescription.entity(forEntityName: "DocumentEntity", in:managedObjectContext)
let newObject = NSManagedObject(entity: entity!, insertInto: managedObjectContext)
return newObject
}