Navigation

Read & Write Data - iOS SDK

The examples on this page use the following models:

class DogToy: Object {
@objc dynamic var name = ""
}
class Dog: Object {
@objc dynamic var name = ""
@objc dynamic var age = 0
@objc dynamic var color = ""
@objc dynamic var currentCity = ""
// To-one relationship
@objc dynamic var favoriteToy: DogToy?
}
class Person: Object {
@objc dynamic var id = 0
@objc dynamic var name = ""
// To-many relationship - a person can have many dogs
let dogs = List<Dog>()
// Inverse relationship - a person can be a member of many clubs
let clubs = LinkingObjects(fromType: DogClub.self, property: "members")
override static func primaryKey() -> String? {
return "id"
}
}
class DogClub: Object {
@objc dynamic var name = ""
let members = List<Person>()
}

If you know the primary key for a given object, you can look it up directly with Realm.object(ofType:forPrimaryKey:).

let realm = try! Realm()
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)

To query for objects of a given type in a realm, pass the metatype instance YourClassName.self to Realm.objects(_:). This returns a Results object representing all objects of the given type in the realm.

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)

A filter selects a subset of results based on the value(s) of one or more object properties. Realm Database provides a full-featured query engine that you can use to define filters.

To filter, call Results.filter(_:) with a query predicate.

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)
// Filter by age
let puppies = dogs.filter("age < 2")
// Filter by person
let dogsWithoutFavoriteToy = dogs.filter("favoriteToy == nil")
// Filter by person's name
let dogsWhoLikeTennisBalls = dogs.filter("favoriteToy.name == 'Tennis ball'")
Tip
Filter on Related and Embedded Object Properties

To filter a query based on a property of an embedded object or a related object, use dot-notation as if it were in a regular, nested object.

The types in your predicate must match the types of the properties. Avoid comparing ObjectId properties to strings, as Realm Database does not automatically convert strings to ObjectIds.

The following example shows the correct and incorrect way to write a query with an ObjectId given the following Realm object:

class User: Object {
@objc dynamic var id = ObjectId.generate()
@objc dynamic var name = ""
}
let realm = try! Realm()
let users = realm.objects(User.self)
// Get specific user by ObjectId id
let specificUser = users.filter("id = %@", ObjectId("11223344556677889900aabb")).first
// WRONG: Realm will not convert the string to an object id
// users.filter("id = '11223344556677889900aabb'") // not ok
// users.filter("id = %@", "11223344556677889900aabb") // not ok

A sort operation allows you to configure the order in which Realm Database returns queried objects. You can sort based on one or more properties of the objects in the results collection. Realm Database only guarantees a consistent order of results if you explicitly sort them.

To sort, call Results.sorted(byKeyPath:ascending:) with the desired key path to sort by.

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)
let dogsSorted = dogs.sorted(byKeyPath: "name", ascending: false)
// You can also sort on the members of linked objects. In this example,
// we sort the dogs by their favorite toys' names.
let dogsSortedByFavoriteToyName = dogs.sorted(byKeyPath: "favoriteToy.name")
Tip
Sort on Related and Embedded Object Properties

To sort a query based on a property of an embedded object or a related object, use dot-notation as if it were in a regular, nested object.

You can query through a relationship the same way you would access a member of a regular Swift or Objective-C object.

let realm = try! Realm()
// Establish a relationship
let dog = Dog()
dog.name = "Rex"
dog.age = 10
let person = Person()
person.id = 12345
person.dogs.append(dog)
try! realm.write {
realm.add(person)
}
// Later, query the specific person
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)
// Access directly through a relationship
let specificPersonDogs = specificPerson!.dogs
let firstDog = specificPersonDogs[0]
print("# dogs: \(specificPersonDogs.count)")
print("First dog's name: \(firstDog.name)")

You can query through an inverse relationship the same way you would access a member of a regular Swift or Objective-C object.

let realm = try! Realm()
// Establish an inverse relationship
let person = Person()
person.id = 12345
let club = DogClub()
club.name = "Pooch Pals"
club.members.append(person)
try! realm.write {
realm.add(club)
}
// Later, query the specific person
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)
// Access directly through an inverse relationship
let clubs = specificPerson!.clubs
let firstClub = clubs[0]
print("# memberships: \(clubs.count)")
print("First club's name: \(firstClub.name)")

You can use Realm's aggregation operators for sophisticated queries against list properties.

let realm = try! Realm()
let people = realm.objects(Person.self)
// People whose dogs' average age is 5
people.filter("dogs.@avg.age == 5")
// People with older dogs
people.filter("dogs.@min.age > 5")
// People with younger dogs
people.filter("dogs.@max.age < 2")
// People with many dogs
people.filter("dogs.@count > 2")
// People whose dogs' ages combined > 10 years
people.filter("dogs.@sum.age > 10")

Because results are lazily evaluated, you can chain several queries together. Unlike traditional databases, this does not require a separate trip to the database for each successive query.

Example

To get a result set for tan dogs, and tan dogs whose names start with ‘B’, chain two queries like this:

let realm = try! Realm()
let tanDogs = realm.objects(Dog.self).filter("color = 'tan'")
let tanDogsWithBNames = tanDogs.filter("name BEGINSWITH 'B'")

To add an object to a realm, instantiate it as you would any other object and then pass it to Realm.add(_:update:) inside of a write transaction.

// Instantiate the class. For convenience, you can initialize
// objects from dictionaries with appropriate keys and values.
let dog = Dog(value: ["name": "Max", "age": 5])
let realm = try! Realm()
// Open a thread-safe transaction.
try! realm.write {
// Add the instance to the realm.
realm.add(dog)
}

You can initialize an object by passing an initializer value to Object.init(value:). The initializer value can be a key-value coding compliant object, a dictionary, or an array containing one element for each managed property.

Note

When using an array as an initializer value, you must include all properties in the same order as they are defined in the model.

You can even initialize related or embedded objects by nesting initializer values:

// Instead of using pre-existing dogs...
let aPerson = Person(value: [123, "Jane", [aDog, anotherDog]])
// ...we can create them inline
let anotherPerson = Person(value: [123, "Jane", [["Buster", 5], ["Buddy", 6]]])

Realm does not directly support JSON, but you can use JSONSerialization.jsonObject(with:options:) to convert JSON into a value that you can pass to Realm.create(_:value:update:).

// Specify a dog toy in JSON
let data = "{\"name\": \"Tennis ball\"}".data(using: .utf8)!
let realm = try! Realm()
// Insert from data containing JSON
try! realm.write {
let json = try! JSONSerialization.jsonObject(with: data, options: [])
realm.create(DogToy.self, value: json)
}

Nested objects or arrays in the JSON map to to-one or to-many relationships.

The JSON property names and types must match the destination object schema exactly. For example:

  • float properties must be initialized with float-backed NSNumbers.
  • Date and Data properties cannot be inferred from strings. Convert them to the appropriate type before passing to Realm.create(_:value:update:).
  • Required properties cannot be null or missing in the JSON.

Realm ignores any properties in the JSON not defined in the object schema.

Tip

If your JSON schema doesn't exactly align with your Realm objects, consider using a third-party framework to transform your JSON. There are many model mapping frameworks that work with Realm. See a partial list in the realm-cocoa repository.

To copy an object from one realm to another, pass the original object to Realm.create(_:value:update:)::

let realm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "first realm"))
try! realm.write {
let dog = Dog()
dog.name = "Wolfie"
dog.age = 1
realm.add(dog)
}
// Later, fetch the instance we want to copy
let wolfie = realm.objects(Dog.self).first(where: { $0.name == "Wolfie" })!
// Open the other realm
let otherRealm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "second realm"))
try! otherRealm.write {
// Copy to the other realm
let wolfieCopy = otherRealm.create(type(of: wolfie), value: wolfie)
wolfieCopy.age = 2
// Verify that the copy is separate from the original
XCTAssertNotEqual(wolfie.age, wolfieCopy.age)
}
Important

The create methods do not support handling cyclical object graphs. Do not pass in an object containing relationships involving objects that refer back to their parents, either directly or indirectly.

You can modify properties of a Realm object inside of a write transaction in the same way that you would update any other Swift or Objective-C object.

let realm = try! Realm()
// Get a dog to update
let dog = realm.objects(Dog.self).first!
// Open a thread-safe transaction
try! realm.write {
// Update some properties on the instance.
// These changes are saved to the realm
dog.name = "Wolfie"
dog.age += 1
}
Tip
Update Related and Embedded Objects

To update a property of an embedded object or a related object, modify the property with dot-notation or bracket-notation as if it were in a regular, nested object.

Object, Result, and List all conform to key-value coding. This can be useful when you need to determine which property to update at runtime.

Applying KVC to a collection is a great way to update objects in bulk. Avoid the overhead of iterating over a collection while creating accessors for every item.

let realm = try! Realm()
let allDogs = realm.objects(Dog.self)
try! realm.write {
allDogs.first?.setValue("Sparky", forKey: "name")
// Move the dogs to Toronto for vacation
allDogs.setValue("Toronto", forKey: "currentCity")
}
Tip

You can also add values for embedded objects or relationships this way. See Initialize Objects with a Value.

To upsert an object, call Realm.add(_:update:) with the second parameter, update policy, set to .modified. The operation either inserts a new object with the given primary key or updates an existing object that already has that primary key.

let realm = try! Realm()
try! realm.write {
let person1 = Person(value: ["id": 1234, "name": "Jones"])
// Add a new person to the realm. Since nobody with ID 1234
// has been added yet, this adds the instance to the realm.
realm.add(person1, update: .modified)
let person2 = Person(value: ["id": 1234, "name": "Bowie"])
// Judging by the ID, it's the same person, just with a
// different name. When `update` is:
// - .modified: update the fields that have changed.
// - .all: replace all of the fields regardless of
// whether they've changed.
// - .error: throw an exception if a key with the same
// primary key already exists.
realm.add(person2, update: .modified)
}

To delete an object from a realm, pass the object to Realm.delete(_:) inside of a write transaction.

try! realm.write {
// Delete the instance from the realm.
realm.delete(dog)
}
Important
Do not use objects after delete

You cannot access or modify an object after you have deleted it from a realm. If you try to use a deleted object, Realm Database throws an error.

To delete a collection of objects from a realm, pass the collection to Realm.delete(_:) inside of a write transaction.

let realm = try! Realm()
try! realm.write {
// Find dogs younger than 2 years old.
let puppies = realm.objects(Dog.self).filter("age < 2")
// Delete the objects in the collection from the realm.
realm.delete(puppies)
}

To delete all objects of a given object type from a realm, pass the result of Realm.objects(_:) for the type you wish to delete to Realm.delete(_:) inside of a write transaction.

let realm = try! Realm()
try! realm.write {
// Delete all instances of Dog from the realm.
let allDogs = realm.objects(Dog.self)
realm.delete(allDogs)
}

To delete all objects from the realm, call Realm.deleteAll() inside of a write transaction. This clears the realm of all object instances but does not affect the realm's schema.

let realm = try! Realm()
try! realm.write {
// Delete all objects from the realm.
realm.deleteAll()
}
Give Feedback