Skip to content

Instantly share code, notes, and snippets.

@philosopherdog
Forked from kharmabum/realm-cheatsheet.md
Created February 25, 2024 23:04
Show Gist options
  • Save philosopherdog/5d4ffd0ebdde688b96384dd750a30564 to your computer and use it in GitHub Desktop.
Save philosopherdog/5d4ffd0ebdde688b96384dd750a30564 to your computer and use it in GitHub Desktop.

Declaring models

class Dog: Object {

  dynamic var id = ""

  dynamic var name = ""

  dynamic var tempVariable = ""

  override static func primaryKey() -> String? { return "id" }

  override static func indexedProperties() -> [String] {

    return ["name"]
  }

  override static func ignoredProperties() -> [String] {
    return ["tempVariable"]
  }
}

class Person: Object {

  dynamic var id = ""

  dynamic var name = ""

  dynamic var picture: NSData? = nil // optionals supported, 16 mb max

  let dogs = List<Dog>()

  override static func primaryKey() -> String? { return "id" }

  override static func indexedProperties() -> [String] {

    return ["name"]
  }
}
  • Properties can be Bool, Int8, Int16, Int32, Int64, Double, Float, String, NSDate truncated to the second, and NSData (computed properties for NSDate recommended)
  • String, NSDate, NSData and Object properties can be optional
  • to-many relationships are defined using List
  • optional variatns of Int, Float, Double, Bool are declared with RealmOptional
  • Properties should be declared with dynamic varexcept those of type List or RealmOptional
  • Realm object settters and getters cannot be overriden
  • Note that Lists can only contain subclasses of Object (polymorphism is not supoorted)
  • No support for array properties
  • Temporary variables is not reccomended (their values are set to default upon refresh/write).

Backlinks - Inverse relationships

class Dog: Object {
    dynamic var name = ""
    dynamic var age = 0
    var owners: [Person] {
        // Realm doesn't persist this property because it only has a getter defined
        // Define "owners" as the inverse relationship to Person.dogs
        return linkingObjects(Person.self, forProperty: "dogs")
    }
}

Using models

  • Property acess (e.g. rex.owner.address.country) will traverse the object graph and auto fetch each object from Realm as needed.
  • You can only acess methods/properties from an object on the thread on which it was created.
  • To share objects between threads or re-use them between app launches a persist operation which must be done within a write transaction.
do {
  let realm = try Realm()
} catch let error as NSError {
  // handle error
}
  • All persisted (non-ignored) properties on Object subclasses are KVO-compliant, along with the invalidated property on Object and List.
  • You cannot add an object to a Realm (with realm.add(obj) or other similar methods) while it has any registered KVO observers.

Seeing changes from other threads

  • A new realm must be inialized per thread (with the same configuration)

  • Within a thread a cached instance is used

  • Unpersisted instances of Objects are safe to pass across threads (otherwise crash on access)

  • Re-fetching will retrieve an instance at the version of the target thread, which may differ from the originating thread that prompted the fetch.

  • On getting updates:

When you initially open a Realm, its state will be based off the most recent successful write commit, and it will remain on that version until refreshed. Realms are automatically refreshed at the start of every runloop iteration, unless Realm’s autorefresh property is set to NO. If a thread has no runloop (which is generally the case in a background thread), then Realm.refresh() must be called manually in order to advance the transaction to the most recent state.

Realms are also refreshed (on all threads) when write transactions are committed (Realm.commitWrite()).

Notifications

  • The observer stays active as long as a reference is held to the returned notification token.
// Observe Realm Notifications
let token = realm.addNotificationBlock { notification, realm in
    viewController.updateUI()
}

Creating objects

// (1) Create and set properties
var myDog = Dog()
myDog.name = "Rex"
myDog.age = 10

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

// (3) Create a Dog object from an array
let myThirdDog = Dog(value: ["Fido", 5])

// Nested objects
//
// Instead of using already existing dogs...
let aPerson = Person(value: ["Jane", 30, [aDog, anotherDog]])

// ...we can create them inline
let anotherPerson = Person(value: ["Jane", 30, [["Buster", 5], ["Buddy", 6]]])

Updating

  • Writes block eachother and will block a thread if multiple are in progress
// Update an object with a transaction
try! realm.write {
  author.name = "Thomas Pynchon"
}

// Creating a book with the same primary key as a previously saved book
let cheeseBook = Book()
cheeseBook.title = "Cheese recipes"
cheeseBook.price = 9000
cheeseBook.id = 1

// Updating book with id = 1
try! realm.write {
  realm.add(cheeseBook, update: true)
}

// Partial update
//
// Assuming a "Book" with a primary key of `1` already exists.
try! realm.write {
  realm.create(Book.self, value: ["id": 1, "price": 9000.0], update: true)
  // the book's `title` property will remain unchanged.
}

// Updates via KVC
let persons = realm.objects(Person)
try! realm.write {
  persons.first?.setValue(true, forKeyPath: "isFirst")
  // set each person's planet property to "Earth"
  persons.setValue("Earth", forKeyPath: "planet") // faster than iterating/reading a List
}

// Updating on a background threads
dispatch_async(queue) {
  autoreleasepool {
    // Get realm and table instances for this thread
    let realm = try! Realm()

    // Break up the writing blocks into smaller portions
    // by starting a new transaction
    for idx1 in 0..<1000 {
      realm.beginWrite()

      // Add row via dictionary. Property order is ignored.
      for idx2 in 0..<1000 {
        realm.create(Person.self, value: [
          "name": "\(idx1)",
          "birthdate": NSDate(timeIntervalSince1970: NSTimeInterval(idx2))
        ])
      }

      // Commit the write transaction
      // to make this data available to other threads
      try! realm.commitWrite()
    }
  }
}

Deleting

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

Querying

  • All reads (including queries and property access) are lazy in Realm.
  • The Result of a query is auto-updating i.e. doesn't need to be refetched
  • Therefore indices and counts are variable
let puppies = realm.objects(Dog).filter("age < 2")
puppies.count // => 0
try! realm.write {
  realm.create(Dog.self, value: ["name": "Fido", "age": 1])
}
puppies.count // => 1

Filtering and sorting

// Query using a predicate string
var tanDogs = realm.objects(Dog).filter("color = 'tan' AND name BEGINSWITH 'B'").sorted("name")

// Query using an NSPredicate
let predicate = NSPredicate(format: "color = %@ AND name BEGINSWITH %@", "tan", "B")
tanDogs = realm.objects(Dog).filter(predicate)

Configuration

Setting the default configuration

func setDefaultRealmForUser(username: String) {
  var config = Realm.Configuration()

  // Use the default directory, but replace the filename with the username
  config.path = NSURL.fileURLWithPath(config.path!)
                  .URLByDeletingLastPathComponent?
                  .URLByAppendingPathComponent("\(username).realm")
                  .path

  // Set this as the configuration used for the default Realm
  Realm.Configuration.defaultConfiguration = config
}

Configuring a Realm

let config = Realm.Configuration(
    // Get the path to the bundled file
    path: NSBundle.mainBundle().pathForResource("MyBundledData", ofType:"realm"),
    // Open the file in read-only mode as application bundles are not writeable
    readOnly: true)

// Open the Realm with the configuration
let realm = try! Realm(configuration: config)

// Read some data from the bundled Realm
let results = realm.objects(Dog).filter("age > 5")

In memory Realm

let realm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "MyInMemoryRealm"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment