使用包含

时间:2017-01-25 10:21:21

标签: ios swift swift3 nsmanagedobject

您好我是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
}
}

1 个答案:

答案 0 :(得分:0)

我知道这是一个老问题,但对于正在寻找此问题的任何人来说,如果您想要唯一的数据,您可以做的就是添加如下所示的约束

enter image description here

然后在您的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
}()

我们添加了一项合并策略,因此如果已经存在数据,它将更新,如果没有,它将插入