Object Models - Swift SDK
On this page
- Key Concept: Object Types & Schemas
- Realm Schema
- Model Inheritance
- Swift Structs
- Key Concept: Properties
- Key Concept: View Models with Realm
- Define a New Object Type
- Declare Properties
- Persisted Property Attributes
- Objective-C Dynamic Property Attributes
- Specify an Optional/Required Property
- Specify a Primary Key
- Index a Property
- Ignore a Property
- Declare Enum Properties
- Remap a Property Name
- Define a Class Projection
- About These Examples
- How to Define a Class Projection
- Define an Asymmetric Object
Key Concept: Object Types & Schemas
Realm Database applications model data as objects composed of field-value pairs that each contain one or more supported data types.
Realm objects are regular Swift or Objective-C classes, but they also bring a few additional features like live queries. The Swift SDK memory maps Realm objects directly to native Swift or Objective-C objects, which means there's no need to use a special data access library, such as an ORM. Instead, you can work with Realm objects as you would any other class instance.
Every Realm object conforms to a specific object type, which is essentially a class that defines the properties and relationships for objects of that type. Realm guarantees that all objects in a realm conform to the schema for their object type and validates objects whenever they're created, modified, or deleted.
Example
The following schema defines a Dog
object type with a string name,
optional string breed, date of birth, and primary key ID.
Realm Schema
A realm schema is a list of valid object schemas that a realm may contain. Every Realm object must conform to an object type that's included in its realm's schema.
By default, the Swift SDK automatically adds all classes in your project that derive from RLMObject or RLMEmbeddedObject to the realm schema.
Tip
Configure Your Realm Schema
To control which classes Realm adds to a realm schema, see Provide a Subset of Classes to a Realm.
If a realm already contains data when you open it, Realm Database validates each object to ensure that an object schema was provided for its type and that it meets all of the constraints specified in the schema.
Tip
Learn How to Work With a Realm
For code examples that show how to configure and open a realm in the Swift SDK, see Configure & Open a Realm - Swift SDK.
Model Inheritance
You can subclass Realm Database models to share behavior between classes, but there are limitations. In particular, Realm does not allow you to:
Cast between polymorphic classes: subclass to subclass, subclass to parent, parent to subclass
Query on multiple classes simultaneously: for example, "get all instances of parent class and subclass"
Multi-class containers:
List
andResults
with a mixture of parent and subclass
Tip
Check out the code samples for working around these limitations.
New in version 10.10.0: While you can't mix @Persisted
and @objc dynamic
property declarations
within a class, you can mix the notation styles across base and subclasses.
For example, a base class could have a @Persisted var foo: Int
property,
and a subclass could have an @objc dynamic var bar = 0
property, with
both persisted. However, the @objc dynamic
property would be ignored if
the @Persisted
property were within the same base or subclass.
Swift Structs
Realm Database does not support Swift structs as models for a variety of reasons. Realm's design focuses on "live" objects. This concept is not compatible with value type structs. By design, Realm provides features that are incompatible with these semantics, such as:
Low memory footprint of data
Good operation performance
Lack of data serialization/deserialization
That said, it is sometimes useful to detach objects from their backing realm. This typically isn't an ideal design decision. Instead, developers use this as a workaround for temporary limitations in our library.
You can use key-value coding to initialize an unmanaged object as a copy of a managed object. Then, you can work with that unmanaged object like any other NSObject.
let standaloneModelObject = MyModel(value: persistedModelObject)
Key Concept: Properties
Your Realm object model is a collection of properties. On the most basic level, when you create your model, your declarations give Realm information about each property:
The data type and whether the property is optional or required
Whether Realm should store or ignore the property
Whether the property is a primary key or should be indexed
Properties are also the mechanism for establishing relationships between Realm object types.
The Realm Swift SDK uses reflection to determine the properties
in your models at runtime. Your project must not set
SWIFT_REFLECTION_METADATA_LEVEL = none
, or Realm cannot discover
children of types, such as properties and enum cases. Reflection is enabled
by default if your project does not specifically set a level for this setting.
Key Concept: View Models with Realm
New in version 10.21.0.
You can work with a subset of your Realm Database object's properties by creating a class projection. A class projection is a class that passes through or transforms some or all of your Realm Database object's properties. Class projection enables you to build view models that use an abstraction of your object model. This simplifies using and testing Realm Database objects in your application.
With class projection, you can use a subset of your object's properties directly in the UI or transform them. When you use a class projection for this, you get all the benefits of Realm Database's live objects:
The class-projected object live updates
You can observe it for changes
You can apply changes directly to the properties in write transactions
Tip
See also:
Define a New Object Type
Note
Class names are limited to a maximum of 57 UTF-8 characters.
Declare Properties
When you declare the property attributes of a class, you can specify whether or not those properties should be managed by the realm. Managed properties are stored or updated in the database. Ignored properties are not stored to the database. You can mix managed and ignored properties within a class.
The syntax to mark properties as managed or ignored varies depending on which version of the SDK you use.
Persisted Property Attributes
New in version 10.10.0: The @Persisted
declaration style replaces the @objc dynamic
,
RealmOptional
, and RealmProperty
declaration notations from older
versions of the SDK. For an older version of the SDK, see:
Objective-C Dynamic Property Attributes.
Declare model properties that you want to store to the database as
@Persisted
. This enables them to access the underlying database data.
When you declare any properties as @Persisted
within a class, the other
properties within that class are automatically ignored.
If you mix @Persisted
and @objc dynamic
property declarations within
a class definition, any property attributes marked as @objc dynamic
will
be ignored.
Tip
See also:
Our Supported Property Types page contains a property declaration cheatsheet.
Objective-C Dynamic Property Attributes
Changed in version 10.10.0: This property declaration information is for versions of the SDK before 10.10.0.
Declare dynamic Realm model properties in the Objective-C runtime. This enables them to access the underlying database data.
You can either:
Use
@objc dynamic var
to declare individual propertiesUse
@objcMembers
to declare a class. Then, declare individual properties withdynamic var
.
Use let
to declare LinkingObjects
, List
, RealmOptional
and
RealmProperty
. The Objective-C runtime cannot represent these
generic properties.
Changed in version 10.8.0: RealmProperty
replaces RealmOptional
Tip
See also:
Our Supported Property Types page contains a property declaration cheatsheet.
Tip
For reference on which types Realm Database supports for use as properties, see Supported Property Types.
Note
Property names are limited to a maximum of 63 UTF-8 characters.
Specify an Optional/Required Property
Specify a Primary Key
You can designate a property as the primary key of your class.
Primary keys allow you to efficiently find, update, and upsert objects.
Primary keys are subject to the following limitations:
You can define only one primary key per object model.
Primary key values must be unique across all instances of an object in a realm. Realm Database throws an error if you try to insert a duplicate primary key value.
Primary key values are immutable. To change the primary key value of an object, you must delete the original object and insert a new object with a different primary key value.
Embedded objects cannot define a primary key.
Index a Property
You can create an index on a given property of your model. Indexes speed up queries using equality and IN operators. They make insert and update operation speed slightly slower. Indexes use memory and take up more space in the realm file. Each index entry is a minimum of 12 bytes. It's best to only add indexes when optimizing the read performance for specific situations.
Realm supports indexing for string, integer, boolean, Date
, UUID
,
ObjectId
, and AnyRealmValue
properties.
New in version 10.8.0: UUID
and AnyRealmValue
types
Ignore a Property
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.
Declare Enum Properties
Remap a Property Name
New in version 10.33.0.
You can map the public name of a property in your object model to a different private name to store in the realm. You might want to do this if your Device Sync schema property names use snake case, for example, while your project uses Swift-idiomatic camel case.
Declare the name you want to use in your project as the @Persisted
property on the object model. Then, pass a dictionary containing the
public and private values for the property names via the
propertiesMapping()
function.
In this example, firstName
is the public property name we use in the code
throughout the project to perform CRUD operations. Using the propertiesMapping()
function, we map that to store values using the private property name
first_name
in the realm. If we write to a synced realm, the Sync
schema sees the values stored using the private property name first_name
.
class Person: Object { var firstName = "" var lastName = "" override class public func propertiesMapping() -> [String: String] { ["firstName": "first_name", "lastName": "last_name"] } }
Define a Class Projection
About These Examples
The examples in this section use a simple data set. The two Realm object
types are Person
and an embedded object Address
. A Person
has
a first and last name, an optional Address
, and a list of friends
consisting of other Person
objects. An Address
has a city and country.
See the schema for these two classes, Person
and Address
, below:
class Person: Object { var firstName = "" var lastName = "" var address: Address? var friends = List<Person>() } class Address: EmbeddedObject { var city: String = "" var country = "" }
How to Define a Class Projection
New in version 10.21.0.
Define a class projection by creating a class of type Projection. Specify the Object
or EmbeddedObject base whose
properties you want to use in the class projection. Use the @Projected
property wrapper to declare a property that you want to project from a
@Persisted
property on the base object.
Note
When you use a List or a MutableSet in a class projection, the type in the class projection should be ProjectedCollection.
class PersonProjection: Projection<Person> { Person.firstName) var firstName // Passthrough from original object (\ Person.address?.city) var homeCity // Rename and access embedded object property through keypath (\ Person.friends.projectTo.firstName) var firstFriendsName: ProjectedCollection<String> // Collection mapping (\}
When you define a class projection, you can transform the original @Persisted
property in several ways:
Passthrough: the property is the same name and type as the original object
Rename: the property has the same type as the original object, but a different name
Keypath resolution: use keypath resolution to access properties of the original object, including embedded object properties
Collection mapping: Project lists or mutable sets of
Object
s orEmbeddedObject
s as a collection of primitive valuesExclusion: when you use a class projection, the underlying object's properties that are not
@Projected
through the class projection are excluded. This enables you to watch for changes to a class projection and not see changes for properties that are not part of the class projection.
Define an Asymmetric Object
New in version 10.29.0.
If your app uses Flexible Sync, you can use Asymmetric Sync to sync an object unidirectionally from your device to the database linked to your Atlas App Services App. Define an asymmetric object by inheriting from AsymmetricObject.
class WeatherSensor: AsymmetricObject { true) var _id: ObjectId (primaryKey: var deviceId: String var temperatureInFahrenheit: Float var barometricPressureInHg: Float var windSpeedInMph: Int }
AsymmetricObjects
broadly support the same property types as Object
,
with a few exceptions:
- Asymmetric objects can only link to embedded objects
Object
andList<Object>
properties are not supportedEmbeddedObject
andList<EmbeddedObject>
are supported
You cannot link to an AsymmetricObject
from within an Object
. Doing so
throws an error.
Asymmetric objects do not function in the same way as other Realm Objects. You cannot:
Add an asymmetric object to a realm
Remove an asymmetric object from a realm
Query an asymmetric object
You can only create an Asymmetric object, which then syncs unidirectionally to the Atlas database linked to your App with Device Sync.
For more information, see: Create an Asymmetric Object.