Realm CRUD Recipe

October 6, 2019 · 5 minute read

Quick list of CRUD (Create, Read, Update, Delete) for (Realm)[realm.io].

##Creating Objects 1. Define a simple model without a primary key

	class Dog: Object
	{
		@objc dynamic var name = ""
		@objc dynamic var age = 0
	}
  1. Define a model with a primary key

    importRealmSwift 
    
    class Worksheet: Object
    {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var title: String = ""
    @objc dynamic var instructions: String = ""
    @objc dynamic var template: String = ""
    @objc dynamic var image: String? = nil
    let problemSet = List<(Problem)>()
        
    convenience init(id: String, title: String, instructions: String, template: String, image: String? = nil, problem: Problem)
    {
        self.init()
        self.id = id
        self.title = title
        self.instructions = instructions
        self.template = template
        self.image = image
        self.problemSet.append(problem)
    }
        
    override static func primaryKey() -> String?
    {
        return "id"
    }
    

Saving (Ways to create) new objects: 1. Create a Dog object and then set its properties

	var myDog = Dog()
	myDog.name = "Rex"
	myDog.age = 10
  1. Create a Dog object from a dictionary

    	let myOtherDog = Dog(value: ["name" : "Pluto", "age": 3])
    
  2. Create a Dog object from an array

    	let myThirdDog = Dog(value: ["Fido", 5])
    

The most obvious is to use the designated initializer to create an object. Objects can also be created from dictionaries using appropriate keys and values. Finally, Object subclasses can be instantiated using arrays. The values in the array have to be in the same order as the corresponding properties in the model. Values in an array should correspond to properties stored in the Realm— you shouldn’t specify values for ignored properties, or computed properties.


Nested objects If an object has properties that are Objects or Lists, these can be set recursively using nested arrays and/or dictionaries. You simply replace each object with a dictionary or array representing its properties:

Instead of using already existing dogs…

let aPerson = Person(value: ["Jane", 30, [myDog, myOtherDog]])

// …we can create them inline

let anotherPerson = Person(value: ["Jane", 30, [["Buster", 5], ["Buddy", 6]]])

This will work for any combination of nested arrays and dictionaries. Note that a List may only contain Objects, not basic types such as String.

After the object is created, you can add it to a Realm: THEN: 4. Get the default Realm

	let realm = try! Realm()

You only need to do this once (per thread)

  1. Add to the Realm inside a transaction

    	try! realm.write {
    		realm.add(myDog)
    	}
    

###Reading (Find/Get) Objects 1. Create a method to get all objects

// MARK: - FETCH
    public func getAllProblems() throws -> Results<Problem>
    {
        do
        {
            realm = try Realm()
            return realm!.objects(Problem.self)
        }
        catch
        {
            throw RuntimeError.NoRealmSet
        }
    }
  1. Or to find one object by a field, using a predicate.

    public func findProblemBy(field: String, value: String) throws -> Results<Problem>
    {
        do
        {
            realm = try Realm()
            let predicate = NSPredicate(format: "%K == %@", field, value)
            return realm!.objects(Problem.self).filter(predicate)
        }
        catch
        {
            throw RuntimeError.NoRealmSet
        }
    }
    

##Deleting Objects 1. Pass object to be deleted:

	public func delete(_ problem: Problem) throws
    {
       do
       {
           realm = try Realm()
           try! realm!.write
           {
               realm!.delete(problem)
           }
       }
       catch
       {
           throw RuntimeError.NoRealmSet
       }
    }
  1. Delete all the objects from the realm database

    	try! realm.write 
    	{
    		realm.deleteAll()
    	}
    

##Updates: 1. Typed updates, by setting its properties within a write transaction:

// Update an object with a transaction
	try! realm.write 
	{
		author.name = "Thomas Pynchon"
	}
  1. Key-value coding (KVC) Useful when you need to determine which property to update at runtime: Great way to update objects in bulk, without iterating over a collection while creating accessors for every item.

    	let persons = realm.objects(Person.self)
    	
    	try! realm.write
    	{
    		persons.first?.setValue(true, forKeyPath: "isFirst")
    		// set each person's planet property to "Earth"
    		persons.setValue("Earth", forKeyPath: "planet")
    	}
    

Working with Models that have or don’t have a primary key

If your model has a primary key defined: You can use “add” method. Example:

class Worksheet: Object
{
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var title: String = ""
    @objc dynamic var instructions: String = ""
    @objc dynamic var template: String = ""
    @objc dynamic var image: String? = nil
    let problemSet = List<(Problem)>()
    
    convenience init(id: String, title: String, instructions: String, template: String, image: String? = nil, problem: Problem)
    {
        self.init()
        self.id = id
        self.title = title
        self.instructions = instructions
        self.template = template
        self.image = image
        self.problemSet.append(problem)
    }
    
    override static func primaryKey() -> String?
    {
        return "id"
    }
}
  1. To save the model above, set up the save method like this:

    // MARK: - SAVE
    public func saveWorksheet(_ sheet: Worksheet) throws
    {
        do
        {
            realm = try Realm()
            try realm!.write
            {
                realm!.add(sheet, update: .modified)
            }
        }
        catch RuntimeError.NoRealmSet
        {
           os_log("no Realm database")
        }
        catch
        {
             print("something horrid happened when trying to save a worksheet")
        }
    }
    
  2. If your model doesn’t define a primary key, e.g.

    class Problem: Object
    {
    @objc dynamic var operation: String = ""
    @objc dynamic var solution: String = ""
    @objc dynamic var isFraction: Bool = false
    let operands = List<Int>()
    }
    

You’ll have to use “create” method to save an instance to Realm:

// MARK: - SAVE
    public func saveProblem(_ problem: Problem) throws
    {
        do
        {
            realm = try Realm()
            try realm!.write
            {
                realm!.create(Problem.self, value: problem)
            }
        }
        catch RuntimeError.NoRealmSet
        {
           os_log("no Realm database")
        }
        catch
        {
             print("something horrid happened when trying to create a problem")
        }
    }

Subscribe to my email list for a monthly newsletter and special updates!