Swift - Implement Core Data in iOS

Core Data is one of the most popular frameworks provided by Apple for iOS and macOS apps.  Core Data does more than databases like managing the object graphs, tracking the changes in the data and many more things, which we already seen in our previous article (Introduction to Core Data) . In this post we will see how to save and retrieve data using Core Data frameworks


To demonstrate the working of Core data, let's begin by creating a single View application with core data module selected as below



Checking the Use Core Data box will cause Xcode to generate boilerplate code for what's known as an in  NSPersistentContainer AppDelegate.swift. The consists  NSPersistentContainer of a set of objects that facilitate saving and retrieving information from Core Data. Inside this container is an object to manage the Core Data state as a whole, an object representing the Data Model, and so on.

Data Model

The file TestCoreData.xcdatamodelId  acts as the model layer for the data that we want to save. We can easily add the entity, attributes and relationships from the UI as like any other relational database. Now, let's say we ant to store the name, phone number and location attributes for the User. Select the TestCoreData.xcdatamodelId file and click on "Add Entity" (+) button and name the entity as Contacts. Add name, phone and location as String type attributes



Click on Main.storyboard to open it in Interface Builder. Add the outlets created for textfields and button action which are defined in ViewController.swift as below

    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var phoneTextField: UITextField!

    @IBOutlet weak var locationTextField: UITextField!

    @IBAction func addButton(sender: UIButton) { }
    @IBAction func findButton(sender: UIButton) { }    




Create Records to Core Data
The process of adding the records to Core Data has following tasks

  • Refer to persistentContainer from appdelegate
  • Create the context from persistentContainer
  • Create an entity with Contacts
  • Create new record with this Contacts Entity
  • Set values for the records for each key
Next, define NSManagedObject and NSManagedObjectContext 

             var context: NSManagedObjectContext?
             var newContact: NSManagedObject?

 Let's do everything inside the ViewController.swift and ViewDidLoad() method. As we know the container is setup in the AppDelegates so we need to refer that container, and create a context from this container

             override func viewDidLoad() {
               super.viewDidLoad()
                // Do any additional setup after loading the view.
        
           context = (UIApplication.shared.delegate as!                             AppDelegate).persistentContainer.viewContext
    }

the container is setup in the AppDelegates so we need to refer that container, Now let's create an entity and new user records in the function addButton() as below

    @IBAction func addButton(sender: UIButton) {
        newContact = NSEntityDescription.insertNewObject(forEntityName: "Contacts", into: context!)
        
        newContact?.setValue(nameTextField.text, forKey: "name")
        newContact?.setValue(phoneTextField.text, forKey: "phone")
        newContact?.setValue(locationTextField.text, forKey: "location")
        
        saveContext()
    }

Here saveContext() is a new function, this method is used for saving the context already exist in the AppDelegate, but we can explicitly add this method to save the context in the Database. Note that, we have to wrap this with do try and catch block


   func saveContext () {
        if context!.hasChanges {
            do {
                try context!.save()
                showAlert(titleName: "Success", messageName: "Succesfully Saved")
            } catch {
                let nserror = error as NSError
                NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
                showAlert(titleName: "Fail", messageName: "Failed to Save")
                abort()
            }
        }
    }

This below showAlert is defined to simply display an alert about the save and retrieve records

    func showAlert(titleName: String, messageName: String) {
        let alert = UIAlertController(title: titleName, message: messageName, preferredStyle: UIAlertController.Style.alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }


At this stage, whenever we run our app the new entries will be added to the Core Data records as below

  • Prepare the request of type NSFetchRequest for the entity
  • Fetch the result from context in the form of array 
  • Iterate through an array to get value for the specific key

    @IBAction func findButton(sender: UIButton) {
        
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Contacts")
        var objects = [Any]()
        var matches: NSManagedObject?
        
        let predicateValue = NSPredicate(format: "(name = %@)", nameTextField.text!)
        request.predicate = predicateValue
        
        do {
            objects = try (context?.fetch(request))!
            if objects.count == 0 {
                showAlert(titleName: "Invalid Data", messageName: "No Match Found")
            } else {
                
                matches = (objects[0] as! NSManagedObject)
                
                phoneTextField.text = (matches?.value(forKey: "phone") as! String)
                locationTextField.text = (matches?.value(forKey: "location") as! String)
            }
        } catch {
            print("error")
        }
    }

Comments