Navigation

Define a Realm Object Schema - iOS SDK

You can define a Realm object by deriving from the Object or EmbeddedObject class. The name of the class becomes the table name in the realm, and properties of the class persist in the database. This makes it as easy to work with persisted objects as it is to work with regular Swift objects.

// A dog has an _id primary key, a string name, an optional
// string breed, and a date of birth.
class Dog: Object {
@objc dynamic var _id = ObjectId.generate()
@objc dynamic var name = ""
@objc dynamic var breed: String?
@objc dynamic var dateOfBirth = Date()
override static func primaryKey() -> String? {
return "_id"
}
}
Tip

For reference on which types Realm Database supports for use as properties, see Supported Property Types - iOS SDK.

When declaring non-generic properties, use the @objc dynamic var annotation. The @objc dynamic var attribute turns Realm model properties into accessors for the underlying database data. If the class is declared as @objcMembers (Swift 4 or later), you can declare properties as dynamic var without @objc.

To declare properties of generic types LinkingObjects, List, and RealmOptional, use let. Generic properties cannot be represented in the Objective‑C runtime, which Realm Database uses for dynamic dispatch of dynamic properties.

You can declare String, Date, Data, and ObjectId properties as optional or required (non-optional) using standard Swift syntax. Declare optional numeric types using the RealmOptional type.

class Person: Object {
// Required string property
@objc dynamic var name = ""
// Optional string property
@objc dynamic var address: String?
// Required numeric property
@objc dynamic var ageYears = 0
// Optional numeric property
let heightCm = RealmOptional<Float>()
}

RealmOptional supports Int, Float, Double, Bool, and all of the sized versions of Int (Int8, Int16, Int32, Int64).

Primary keys enforce uniqueness among objects in a realm.

You can efficiently find, update, and upsert objects with a primary key.

As long as an object is managed by a realm, that object's primary key value is immutable.

Override Object.primaryKey() to set the model’s primary key.

class Project: Object {
@objc dynamic var id = 0
@objc dynamic var name = ""
// Return the name of the primary key property
override static func primaryKey() -> String? {
return "id"
}
}

Indexes make queries using equality and IN operators faster in exchange for slightly slower writes. Indexes take up more space in the realm file. It’s best to only add indexes when optimizing the read performance for specific situations.

Realm supports indexing for string, integer, boolean, Date, and ObjectId properties.

To index a property, override Object.indexedProperties() and return a list of indexed property names.

class Book: Object {
@objc dynamic var priceCents = 0
@objc dynamic var title = ""
// Return a list of indexed property names
override static func indexedProperties() -> [String] {
return ["title"]
}
}

Ignored properties behave exactly like normal properties. They can’t be used in queries and won’t trigger Realm notifications. You can still observe them using KVO.

Tip

Realm automatically ignores read-only properties.

If you don’t want to save a field in your model to its realm, override Object.ignoredProperties() and return a list of ignored property names.

class Person: Object {
@objc dynamic var tmpId = 0
@objc dynamic var firstName = ""
@objc dynamic var lastName = ""
// Read-only properties are automatically ignored
var name: String {
return "\(firstName) \(lastName)"
}
// Return a list of ignored property names
override static func ignoredProperties() -> [String] {
return ["tmpId"]
}
}

Realm supports only Int-backed @objc enums.

// Define the enum
@objc enum TaskStatusEnum: Int, RealmEnum {
case notStarted = 1
case inProgress = 2
case complete = 3
}
// To use the enum:
class Task: Object {
@objc dynamic var name: String = ""
@objc dynamic var owner: String?
// Required enum property
@objc dynamic var status = TaskStatusEnum.notStarted
// Optional enum property
let optionalTaskStatusEnumProperty = RealmOptional<TaskStatusEnum>()
}
Tip
See also:

A to-one relationship maps one property to a single instance of another object type. For example, you can model a person having at most one companion dog as a to-one relationship.

class Person: Object {
@objc dynamic var name: String = ""
@objc dynamic var birthdate: Date = Date(timeIntervalSince1970: 1)
// A person can have one dog
@objc dynamic var dog: Dog?
}
class Dog: Object {
@objc dynamic var name: String = ""
@objc dynamic var age: Int = 0
@objc dynamic var breed: String?
// No backlink to person -- one-directional relationship
}

A to-many relationship maps one property to zero or more instances of another object type. For example, you can model a person having any number of companion dogs as a to-many relationship.

Use List tagged with your target type to define your to-many relationship property.

class Person: Object {
@objc dynamic var name: String = ""
@objc dynamic var birthdate: Date = Date(timeIntervalSince1970: 1)
// A person can have many dogs
let dogs = List<Dog>()
}
class Dog: Object {
@objc dynamic var name: String = ""
@objc dynamic var age: Int = 0
@objc dynamic var breed: String?
// No backlink to person -- one-directional relationship
}

An inverse relationship property is an automatic backlink relationship. Realm Database automatically updates implicit relationships whenever an object is added or removed in a corresponding to-many list or to-one relationship property. You cannot manually set the value of an inverse relationship property.

To define an inverse relationship, use LinkingObjects in your object model. The LinkingObjects definition specifies the object type and property name of the relationship that it inverts.

class User: Object {
@objc dynamic var _id: ObjectId = ObjectId.generate()
@objc dynamic var _partition: String = ""
@objc dynamic var name: String = ""
// A user can have many tasks.
let tasks = List<Task>()
override static func primaryKey() -> String? {
return "_id"
}
}
class Task: Object {
@objc dynamic var _id: ObjectId = ObjectId.generate()
@objc dynamic var _partition: String = ""
@objc dynamic var text: String = ""
// Backlink to the user. This is automatically updated whenever
// this task is added to or removed from a user's task list.
let assignee = LinkingObjects(fromType: User.self, property: "tasks")
override static func primaryKey() -> String? {
return "_id"
}
}

An embedded object exists as nested data inside of a single, specific parent object. It inherits the lifecycle of its parent object and cannot exist as an independent Realm object. Realm automatically deletes embedded objects if their parent object is deleted or when overwritten by a new embedded object instance.

Note
Realm Uses Cascading Deletes for Embedded Objects

When you delete a Realm object, any embedded objects referenced by that object are deleted with it. If you want the referenced objects to persist after the deletion of the parent object, your type should not be an embedded object at all. Use a regular Realm object with a to-one relationship instead.

You can define an embedded object by deriving from the EmbeddedObject class. You can use your embedded object in another model as you would any other type.

// Define an embedded object
class Address: EmbeddedObject {
@objc dynamic var street: String?
@objc dynamic var city: String?
@objc dynamic var country: String?
@objc dynamic var postalCode: String?
}
// Define an object with one embedded object
class Contact: Object {
@objc dynamic var _id = ObjectId.generate()
@objc dynamic var name = ""
// Embed a single object.
// Embedded object properties must be marked optional.
@objc dynamic var address: Address?
override static func primaryKey() -> String? {
return "_id"
}
convenience init(name: String, address: Address) {
self.init()
self.name = name
self.address = address
}
}
// Define an object with an array of embedded objects
class Business: Object {
@objc dynamic var name = ""
let addresses = List<Address>() // Embed an array of objects
convenience init(name: String, addresses: [Address]) {
self.init()
self.name = name
self.addresses.append(objectsIn: addresses)
}
}
Give Feedback