Using Realm Mobile Database with Swift 4.0 (Insert, Update, Delete, List)

Using Realm Mobile Database with Swift 4.0 Insert

A big problem that many developers face now a days is dealing with database. To have your app in app store in top list is not quite easy and to make the app ready for scalability is pretty hard. When our app is reached to many users, say a million, we have to care about everything in the app from performance to scalability. As far as I see till date developers have only two options “SQLite” and “Core Data”. Though both have a lot of advantages over each, I love to work with “Core Data” because of ease of dealing with records and persisting data and also due to the native advantages of “Core Data”. Very Recently I started using Realm that can be considered as a perfect replacement for “SQLite” and “Core Data”.

What is Realm?

Realm, it’s a cross platform mobile database for iOS and Android and designed specifically for mobile applications. It is available in both Swift and Objective-C. It is framed to be faster and better than SQLite and CoreData. With just few lines of code a lot of things can be done better and faster. Realm uses its own persistence engine to achieve the better performance and speed.

Why Realm?

1

Light weight and simple to integrate in our project.

2

Better and faster than even raw SQLite on common operations.

3

Automatic and seamless realtime data sync.

4

Supports relationships, generics, vectorization and Swift.

5

Completely free.

Let’s get started…

Let’s get started building simple iPhone app with Swift and Realm. The sample application is just list of users. User can add users with Name and address. Before starting, we need to configure the Xcode and install the tools needed to work with Realm.

Prerequisites:

1

iOS 8 or Later.

2

Xcode 6.3 or later.

3

Realm for Swift.

1. Before proceeding for building an app, please make sure that you have CocoaPods installed. We use CocoaPods for installing Realm in the Xcode project. Several online tutorials can be found to know about CocoaPods.

2. Create a “Single View Application” Xcode project and name it as “RealmSample” or anything you prefer. Make sure Swift is selected as a programming language.

3. Open terminal and navigate to your project directory. Here we configure the CocoaPods. Run the following command in terminal to initialize CocoaPods: $pod init

4. Open the pod file generated with XCode and add pod ‘RealmSwift’,’~>2.7.0’ after your target. The file should look like below

# Uncomment the next line to define a global platform for your project  
# platform :ios, '9.0'  
  
target 'RealmSample' do  
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks  
  use_frameworks!  
  
    pod 'RealmSwift’,'~>2.7.0’  
  # Pods for RealmSample  
  
  target 'RealmSampleTests' do  
    inherit! :search_paths  
    # Pods for testing  
  end  
  
  target 'RealmSampleUITests' do  
    inherit! :search_paths  
    # Pods for testing  
  end  
  
end 

5. Close the pod file and run the command “pod install” in the terminal to download and install the Realm in your project.

6. Once done, we see a new Xcode workspace has been generated with the project name as RealmSample.xcworkspace.

7. Open .xcworkspace file instead of .xcodeproj. Once you open the workspace, you will see something like below:

Xcode Project

8. Open AppDelegate.swift and add the following lines marked in the boxes.

import RealmSwift  
  
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {  
        // Override point for customization after application launch.  
        Realm.Configuration.defaultConfiguration = Realm.Configuration(  
            schemaVersion: 1,  
            migrationBlock: { migration, oldSchemaVersion in  
                if (oldSchemaVersion < 1) {  
                   //write the migration logic here  
                }  
        })  
          
        return true }

9. Our sample is to create the list of users with their general data like first name, lastname, age and gender. Later show the list of users and edit the details of selected user.

10. Let’s create the object classes for the users. Let’s name it as person.swift and have the respective variable define. As below:

import UIKit  
import  RealmSwift  
  
class Person: Object {  
    @objc private(set) dynamic var id = 0  
    @objc private(set) dynamic var firstName = ""  
    @objc private(set) dynamic var lastName = ""  
    var gender = RealmOptional<Int>(0)  
    var age = RealmOptional<Int>(0)  
  
      
    override static func primaryKey() -> String? {  
        return "id"  
    }  
      
    convenience init(id : Int, firstName: String, lastName : String, age:RealmOptional<Int> , gender : RealmOptional<Int>) {  
        self.init()  
        self.id = id  
        self.firstName = firstName  
        self.lastName = lastName  
        self.age = age  
        self.gender = gender  
    }  
  
}

A RealmOptional instance represents an optional value for types that can’t be directly declared as `dynamic` in Swift, such as `Int`, `Float`, `Double`, and `Bool`. To change the underlying value stored by a `RealmOptional` instance, mutate the instance’s `value` property.

11. Let’s create a “RealmManager.swift” class which will manage the database methods like save objects, edit objects, get objects and delete objects. We mainly concentrate on

Add, Edit, Get, Delete and Lists in Realm.

Add (same as insert query)->  realm?.add(objs, update: false)

Edit (same as update query)-> realm?.add(objs, update: true)

Get (same as select query)  -> realm!.objects(type)

Delete (same as delete query) -> realm?.delete(objs)

Delete Total Database -> realm?.deleteAll()

All the above actions should be performed in the try block and we need to check if the database has the write permissions. It can be done by doing

try! realm?.write({  
  
<database operation>  
})

RealmManager.swift:

import Foundation  
import  RealmSwift  
  
class RealmManager {  
    let realm = try? Realm()  
      
    // delete table  
    func deleteDatabase() {  
        try! realm?.write({  
            realm?.deleteAll()  
        })  
    }  
      
    // delete particular object  
    func deleteObject(objs : Object) {  
       try? realm!.write ({  
            realm?.delete(objs)  
    })  
    }  
      
     //Save array of objects to database  
    func saveObjects(objs: Object) {  
        try? realm!.write ({  
            // If update = false, adds the object  
            realm?.add(objs, update: false)  
        })  
    }  
      
    // editing the object  
    func editObjects(objs: Object) {  
        try? realm!.write ({  
            // If update = true, objects that are already in the Realm will be  
            // updated instead of added a new.  
            realm?.add(objs, update: true)  
        })  
    }  
      
     //Returs an array as Results<object>?  
    func getObjects(type: Object.Type) -> Results<Object>? {  
        return realm!.objects(type)  
    }  
      
    func incrementID() -> Int {  
        return (realm!.objects(Person.self).max(ofProperty: "id") as Int? ?? 0) + 1  
    }  
  
}

Adding Details to Database:

12. Create a “AddViewController.swift” class with a simple UI of 4 text fields which represent first name, last name, age and gender and a Save button to save the data in the database.

13. Define the method for Save button to save the person data and add the following code.

func addPersons() {  
          
        // Editing the existing object  
        let age = Int(ageTF.text!)  
        let gender = genderArr.index(of: genderTF.text!)  
          
        if isEditingData == true {  
            let newPerson = Person(id : (personData?.id)! , firstName : firstNameTf.text ?? "" , lastName : lastNameTf.text ?? "" ,age:RealmOptional<Int>(age) ,gender : RealmOptional<Int>(gender))  
            realmManager.editObjects(objs: newPerson)  
        }  
            // Adding the new Object  
        else if isEditingData == false {  
            let id = realmManager.incrementID()  
            let newPerson = Person(id : id , firstName : firstNameTf.text ?? "" , lastName : lastNameTf.text ?? "" ,age:RealmOptional<Int>(age),gender: RealmOptional<Int>(gender))  
            realmManager.saveObjects(objs: newPerson)  
        }  
        self.navigationController?.popViewController(animated: true)  
    }

We can use the same class to edit and add the details. As of now let’s talk about saving the new objects into the database. In the above method you can observe the method saveObjects() method defined in RealmManager.swift which uses realm.add() method with the object to be saved and the update parameter set to false, which implies that new object has to be added to the database.

//Save array of objects to database  
    func saveObjects(objs: Object) {  
        try? realm!.write ({  
            // If update = false, adds the object  
            realm?.add(objs, update: false)  
        })  
    }

Retrieve the data from database and display in the tableView

14. Create a class with list view to display the list of persons added retrieving from database. Let’s say the class name as “ViewController.swift” and add the UITableview to display the list of users.

15. Define an array of type Persons.swift (the object class we created earlier) and add the person objects to that array.

override func viewWillAppear(_ animated: Bool) {  
        super.viewWillAppear(animated)  
        personsArr = [Person]()  
        getAllObjects()  
        self.personsTableView.reloadData()  
    }  
      
    // fetch all the objects in table  
    func getAllObjects() {  
        personsArr = [Person]()  
        if let objects = realmManager.getObjects(type: Person.self) {  
            for element in objects {  
                if let person = element as? Person {  
                    // Do whatever you like with 'person' object  
//                    print("\(person.firstName), \(person.id), \(person.age)")  
                    personsArr.append(person)  
                }  
            }  
        }  
    }

In ViewWillAppear we can define an array “personsArr” of type Person and then call the function “getAllObjects()” which will in-turn call the “getObjects()” from RealmManager.Swift. This will give the persons data stored in database and will reload the tableView.

In RealmManager.swift , getObjects(type:) method will return the objects of type person that we had invoked from ViewController.Swift class. We parse those objects and will be loading in the tableview using respective datasource and delegate methods.

//Returs an array as Results<object>?  
    func getObjects(type: Object.Type) -> Results<Object>? {  
        return realm!.objects(type)  
    }

realm!objects(type)”  this will get the objects of the typed defined. This is something like the “select * from <table>” query in the regular SQLite.

Get the details of selected person from the List view and Edit the details:

Once we load the person details in “ViewController.swift”, we can select the specific user from tableview “didSelectRow” method and navigate to “AddViewController.swift”. We use the same class for both adding and editing the details. From here we populate the selected person details in the textfields. We will have the selected person details with the personArr we had added the persons objects at while retrieving the data.

Edit Details:

After changing any of the details, you can save the details. Depending on the boolean variable “isEditingData” (the variable we use to differentiate to add or edit the details), we pass the edited data to the “editObjects()” method in “RealmManager.swift” class.

func addPersons() {  
          
        // Editing the existing object  
        let age = Int(ageTF.text!)  
        let gender = genderArr.index(of: genderTF.text!)  
          
        if isEditingData == true {  
            let newPerson = Person(id : (personData?.id)! , firstName : firstNameTf.text ?? "" , lastName : lastNameTf.text ?? "" ,age:RealmOptional<Int>(age) ,gender : RealmOptional<Int>(gender))  
            realmManager.editObjects(objs: newPerson)  
        }  
            // Adding the new Object  
        else if isEditingData == false {  
            let id = realmManager.incrementID()  
            let newPerson = Person(id : id , firstName : firstNameTf.text ?? "" , lastName : lastNameTf.text ?? "" ,age:RealmOptional<Int>(age),gender: RealmOptional<Int>(gender))  
            realmManager.saveObjects(objs: newPerson)  
        }  
        self.navigationController?.popViewController(animated: true)  
    }

In RealmManager.swift, add the following the lines of code to edit the details in database

// editing the object  
    func editObjects(objs: Object) {  
        try? realm!.write ({  
            // If update = true, objects that are already in the Realm will be  
            // updated instead of added a new.  
            realm?.add(objs, update: true)  
        })  
    }

The above method will be very similar to the realm.add(), the only difference is we specify the update parameter to true which will specify that the object need to updated in database.

Delete Data:

In “ViewController.swift”, enable tableview editing to true and add the following lines of code.

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {  
        return true  
    }  
      
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {  
        if (editingStyle == UITableViewCellEditingStyle.delete) {  
            // handle delete (by removing the data from your array and updating the tableview)  
            tableView.beginUpdates()  
            let person : Person = personsArr[indexPath.row]  
            // delete an Object  
            realmManager.deleteObject(objs: person)  
            personsArr.remove(at: indexPath.row)  
            tableView.deleteRows(at: [indexPath],  with: UITableViewRowAnimation.automatic)  
            tableView.endUpdates()  
        }  
    }

In RealmManager.swift, the method deleteObject(obj) will perform the deletion of the object from database.

// delete particular object  
    func deleteObject(objs : Object) {  
       try? realm!.write ({  
            realm?.delete(objs)  
    })  
    }

The realm?.delete(objs) will delete the given object from database.

Realm List:

List is the container type in Realm used to define to-many relationships.Like Swift’s Array, List is a generic type that is parameterized on the type of Object it stores.Unlike Swift’s native collections, Lists are reference types, and are only immutable if the Realm that manages them is opened as read-only.Lists can be filtered and sorted with the same predicates as Results<Element>.Properties of List type defined on Object subclasses must be declared as let and cannot be dynamic.

To check with an example

Create the object class Task.swift and add the following lines of code

import Foundation  
import RealmSwift  
  
class Task : Object{  
    @objc dynamic var name = ""  
    @objc dynamic var createdAt = NSDate()  
    @objc dynamic var notes = ""  
    @objc dynamic var isCompleted = false  
      
}

And then create another object class TaskList.swift which will accepts the List type of object.

import Foundation  
import RealmSwift  
  
class TaskList: Object {  
      
    @objc dynamic var name = ""  
    @objc dynamic var createdAt = NSDate()  
    let tasks = List<Task>()      
}

Create a TasksViewController.swift to create the tasks and add that tasks as List and try to add them in the database.

import UIKit  
import Realm  
import RealmSwift  
  
class TasksViewController: UIViewController {  
  
    let realm = try? Realm()  
  
    var lists : Results<TaskList>!  
  
    override func viewDidLoad() {  
        super.viewDidLoad()  
  
        // Do any additional setup after loading the view.  
          
        let taskListA = TaskList()  
        taskListA.name = "TasksToDo"  
          
        let t1 = Task()  
        t1.name = "Morning Walk"  
        t1.notes = "At 6 AM every day"  
          
        let t2 = Task(value: ["name": "BreakFast", "notes": "Pancakes every Monday"])  
        let t3 = Task(value: ["Car", NSDate(), "Auto R8", false])  
          
        taskListA.tasks.append(objectsIn: [t1, t2, t3])  
          
  
        try? realm!.write ({  
            realm?.add([taskListA,taskListA])  
        })  
            lists = realm?.objects(TaskList.self)  
  
            print(lists)  
  
    }  
  
    override func didReceiveMemoryWarning() {  
        super.didReceiveMemoryWarning()  
        // Dispose of any resources that can be recreated.  
    }  
}

Get Realm File to check the database. To get the path of the file you can write the following code in any swift class and run the app on simulator

if let fileUrl = Realm.Configuration.defaultConfiguration.fileURL{  
            print("FILE URL IS",fileUrl)  
        }

Navigate to that file path, you can see default.realm database file. Install Realm Browser to open that file and you can see something like below and you can observer how tasks are saved as List in tasklist table.

Note: After downloading the code, please do run $pod install command from terminal in the project folder path which will create the .xcworkspace file. Open that file to run the code.

The final output:

Using Realm Mobile Database

KalyanKumar Parise
A lead iOS developer committed to collaborative problem solving, sophisticated design, and the creation of quality products for mobile devices powered by Apple’s iOS operating system. Interested to learn and share knowledge about different development platforms. Loves to code both as a hobby and profession. When not coding, will try to explore different subjects over internet and be a loving husband.