您好我是CoreData的新手并且正在探索它。这里的情况是我从API调用下载数据并将其存储在CoreData中,然后从CoreData中获取所有数据。
此任务在viewDidLoad方法上完成。因此,每次打开我的应用程序时,它都会调用此方法并正在下载数据。在视图中,我将所有数据存储在特定键的NSManagedObject数组中。
现在这个流程在我的CoreData中重复了一些条目。所以我想要做的就是保持流量不变。但是每当从API获取数据时,我想检查数据是否在该数组中可用?如果是,则不要将其插入CoreData实体,否则输入数据。这个流程背后的原因是每当API更新时,它只会下载该数据并将其插入到CoreData中,否则它将从Local CoreData本身获取。
这是我的代码:
import UIKit
import CoreData
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
var allImageData:[Any] = []
var image: [NSManagedObject] = []
let urlForData = URL(string: "https://jsonplaceholder.typicode.com/comments")
override func viewDidLoad() {
super.viewDidLoad()
indicator.frame = CGRect(x: CGFloat(0.0), y: CGFloat(0.0), width: CGFloat(40.0), height: CGFloat(40.0))
indicator.center = self.view.center
self.view.addSubview(indicator)
indicator.bringSubview(toFront: self.view)
UIApplication.shared.isNetworkActivityIndicatorVisible = false
indicator.startAnimating()
callToFetchJson()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func callToFetchJson() { //1st This Function will be called
let request = URLRequest(url: urlForData!)
URLSession.shared.dataTask(with: request) { (data, response, error) in
if data == nil && error == nil {
print("no data")
}
else if data != nil && error != nil {
print("Error")
}
else {
DispatchQueue.main.sync {
self.decodingJson(data!)
}
}
}.resume()
}
func saveToDB(_ name: String) {//This function is called to save image name to CoreData and it is called from decodingJson function
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "ImageDetails",
in: managedContext)!
let imageX = NSManagedObject(entity: entity,
insertInto: managedContext)
imageX.setValue(name, forKey: "imageName")
do {
try managedContext.save()
image.append(imageX)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
func decodingJson(_ data: Data ) { //If we get data from API then this function will be called
do {
indicator.stopAnimating()
let allImage = data
allImageData = try JSONSerialization.jsonObject(with: allImage, options: JSONSerialization.ReadingOptions.allowFragments) as! [Any]
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
let entity =
NSEntityDescription.entity(forEntityName: "ImageDetails",
in: managedContext)!
let imageX = NSManagedObject(entity: entity,
insertInto: managedContext)
for xImg in allImageData {
let aImg = xImg as! [String:AnyObject]
let aImgName = aImg["name"] as! String
// I want some condition to check image array contains aImgName or not forKey: imageName
//Here I want a check whether the data we got after decoding json is available in image array or not.
//If it is available then don't call saveToDB func. Otherwise call it.
// Following I have tried
imageX.setValue(aImgName, forKey: "imageName")
if !self.image.contains(imageX) {
saveToDB(aImgName)
print("Data inserted")
}
//Above code is failing to do its task. So is there any other way?
}
self.tableView.reloadData()
}
catch {
}
}
func tableView(_ tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return self.allImageData.count;
}
func tableView(_ tableView: UITableView!, didSelectRowAtIndexPath indexPath: IndexPath!) {
print("You selected item #:\(indexPath.item)")
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell") as! tableViewCell
let imageX = image[indexPath.row]
cell.titleLabel.text = imageX.value(forKey: "imageName") as? String
return cell
}
}
答案 0 :(得分:0)
我知道这是一个老问题,但对于正在寻找此问题的任何人来说,如果您想要唯一的数据,您可以做的就是添加如下所示的约束
然后在您的AppDelegate中添加此
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "MarketPulse")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
return container
}()
我们添加了一项合并策略,因此如果已经存在数据,它将更新,如果没有,它将插入