This is not the current version. View the latest documentation

Getting Started

Installation

Manual Installation (Objective‑C & Swift)

  1. Download the latest release of Realm and extract the zip.
  2. Drag Realm.framework from the ios/ or osx/ directory to the File Navigator of your Xcode project. Make sure Copy items into destination group’s folder is selected and click Finish.
  3. Click on your project in the Xcode File Navigator. Select your app’s target and go to the Build Phases tab. Under Link Binary with Libraries click + and add libc++.dylib.
  4. If using Realm with Swift, drag the file at Swift/RLMSupport.swift into the File Navigator of your Xcode project, checking the Copy items if needed checkbox.
  5. If using Realm in an OSX project, click the + button in the top left of the panel and select New Copy Files Phase. Rename this new phase to Copy Frameworks, set the Destination to Frameworks, and add Realm.framework.

Installation via CocoaPods (Objective‑C Only)

If you use CocoaPods

  1. Add the following to your Podfile: pod "Realm".
  2. From the command line, run pod install.
  3. Use the .xcworkspace file generated by CocoaPods to work on your project!

Xcode Plugin

Our Xcode plugin makes it easy to generate new Realm models.

The easiest way to install the Realm Xcode plugin is through Alcatraz under the name “RealmPlugin”. You can also install the plugin manually by opening plugin/RealmPlugin.xcodeproj contained in the release zip and clicking build. You will need to quit and relaunch Xcode to see our plugin. If you use the Xcode menu to create a new file (File > New > File… — or ⌘N) you should see a new option to create a new Realm model.

Realm Browser

We also provide a standalone app to read and edit .realm databases. You can find it in our release zip under browser/.

You can generate a test database with sample data using the menu item Tools > Generate demo database.

API Reference

You can consult our full API reference for all classes, methods & more.

Examples

You can find example Objective‑C, Swift and RubyMotion applications for both iOS and OSX in our release zip under examples/, demonstrating how to use many features of Realm like migrations, how to use it with UITableViewControllers, encryption, command-line tools and much more.

Getting Help

Models

Realm data models are defined using traditional Objective‑C interfaces with @properties. Simply subclass RLMObject or an existing model class to create your Realm data model objects. Realm model objects mostly function like any other Objective‑C objects - you can add your own methods and protocols to them and use them like you would any other object. The main restrictions are that you can only use an object on the thread which it was created, and you can’t access its ivars directly for any persisted properties.

If you have installed our Xcode Plugin there will be a nice template to create the interface and implementation files in the “New File…” dialog.

Relationships and nested data structures are modeled simply by including properties of the target type or RLMArrays for typed lists of objects.

#import <Realm/Realm.h>

@class Person;

// Dog model
@interface Dog : RLMObject
@property NSString *name;
@property Person   *owner;
@end
RLM_ARRAY_TYPE(Dog) // define RLMArray<Dog>

// Person model
@interface Person : RLMObject
@property NSString      *name;
@property NSDate        *birthdate;
@property RLMArray<Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // define RLMArray<Person>

// Implementations
@implementation Dog
@end // none needed

@implementation Person
@end // none needed
import Realm

// Dog model
class Dog: RLMObject {
    dynamic var name = ""
    dynamic var owner: Person? // Can be optional
}

// Person model
class Person: RLMObject {
    dynamic var name = ""
    dynamic var birthdate = NSDate(timeIntervalSince1970: 1)
    dynamic var dogs = RLMArray(objectClassName: Dog.className())
}

See RLMObject for more details.

Property Types

Realm supports the following property types: BOOL, bool, int, NSInteger, long, float, double, CGFloat, NSString, NSDate, and NSData.

You can use RLMArray\<_Object_\> and RLMObject to model relationships such as to-many and to-one. Subclassing RLMObject is also supported.

Property Attributes

Note that Realm ignores most Objective‑C property attributes, such as nonatomic, atomic, strong, copy, weak, etc., because we use our own optimized storage semantics. The only property that Realm doesn’t ignore is readonly, which has the effect of preventing a property from being persisted.

To avoid being misleading, we recommend writing models without any property attributes at all (except if you want to use readonly). If you do set property attributes, they will be used until the object is added to a Realm.

Custom names for getters and setters work normally regardless of whether or not an object is in a Realm.

Customizing Models

Several class methods exist to further specify model information:

  • +attributesForProperty: can be overriden to provide property-specific attributes like which properties should be indexed.
  • +defaultPropertyValues can be overriden to provide default values every time an object is created.
  • +primaryKey can be overriden to set the model’s primary key. Declaring a primary key allows objects to be looked up and updated efficiently and enforces uniqueness for each value.
  • ignoredProperties can be overriden to prevent Realm from persisting model properties.

Writes

All changes to an object (addition, modification and deletion) have to be done within a write transaction.

Realm objects can be instantiated and used standalone just like regular objects. To share objects between threads or re-use them between app launches you must persist them to a Realm, an operation which must be done within a write transaction. You can add an object to a Realm like so:

// Create object
Person *author = [[Person alloc] init];
author.name    = @"David Foster Wallace";

// Get the default Realm
RLMRealm *realm = [RLMRealm defaultRealm];
// You only need to do this once (per thread)

// Add to Realm with transaction
[realm beginWriteTransaction];
[realm addObject:author];
[realm commitWriteTransaction];
// Create a Person object
let author = Person()
author.name = "David Foster Wallace"

// Get the default Realm
let realm = RLMRealm.defaultRealm()
// You only need to do this once (per thread)

// Add to the Realm inside a transaction
realm.beginWriteTransaction()
realm.addObject(author)
realm.commitWriteTransaction()

After you have added the object to the Realm you can continue using it, and all changes you make to it will be persisted (and must be made within a write transaction). Any changes are made available to other threads that use the same Realm when the write transaction is committed.

Please note that writes block each other, and will block the thread they are made on if multiple writes are in progress. This is similar to other persistence solutions and we recommend that you use the usual best-practices for this situation, namely offloading your writes to a separate thread

Due to Realm’s MVCC architecture, reads are not blocked while a write transaction is open. Unless you need to make simultaneous writes from many threads at once, you should favor larger write transactions that do more work over many fine-grained write transactions.

See RLMRealm and RLMObject for more details.

Queries

Queries return an RLMResults object, which contains a collection of RLMObjects. RLMResults have an interface very similar to NSArray and objects contained in an RLMResult can be accessed using indexed subscripting. Unlike NSArrays, RLMResults are typed and only hold RLMObjects of a single subclass type. For more details see RLMResults.

All queries (including queries and property access) are lazy in Realm. Data is only read when the properties are accessed.

Results to a query are not copies of your data: modifying the results of a query (within a write transaction) will modify the data on disk directly. Similarly, you can traverse your graph of relationships directly from the RLMObjects contained in an RLMResult.

Retrieving Objects by Type

The most basic method for retrieving objects from a Realm is [RLMObject allObjects], which returns an RLMResults of all RLMObject instances of the subclass type being queried the default Realm.

// Query the default Realm
RLMResults *dogs = [Dog allObjects]; // retrieves all Dogs from the default Realm

// Query a specific Realm
RLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // get a specific Realm
RLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // retrieve all Dogs from that Realm
// Query the default Realm
let dogs = Dog.allObjects()

// Query a specific Realm
let petsRealm = RLMRealm(path: "pets.realm")
let otherDogs = Dog.allObjectsInRealm(petsRealm)

Querying with Predicates

If you’re familiar with NSPredicate, then you already know how to query in Realm. RLMObjects, RLMRealm, RLMArray, and RLMResults all provide methods that allow you to query for specific RLMObjects instances by simply passing in an NSPredicate instance, predicate string, or predicate format string just as you would when querying an NSArray.

For example, the following would extend our earlier example by calling [RLMObject objectsWhere:] to retrieve all dogs with the color tan and names beginning with ‘B’ from the default Realm:

// Query using a predicate string
RLMResults *tanDogs = [Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];

// Query using an NSPredicate object
NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@",
                                                     @"tan", @"B"];
tanDogs = [Dog objectsWithPredicate:pred];
// Query using a predicate string
var tanDogs = Dog.objectsWhere("color = 'tan' AND name BEGINSWITH 'B'")

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

See Apple’s Predicates Programming Guide for more information about building predicates. Realm supports many common predicates:

  • The comparison operands can be property names or constants. At least one of the operands must be a property name.
  • The comparison operators ==, <=, <, >=, >, !=, and BETWEEN are supported for int, long, float, double, and NSDate property types. Such as age == 45
  • Identity comparisons ==, !=, e.g. [Employee objectsWhere:@”company == %@”, company]
  • The comparison operators == and != are supported for bool properties.
  • For NSString and NSData properties, we support the ==, !=, BEGINSWITH, CONTAINS, and ENDSWITH operators, such as name CONTAINS ‘Ja’
  • Case insentive comparisons for strings, such as name CONTAINS[c] ‘Ja’
  • Realm supports the following compound operators: “AND”, “OR”, and “NOT”. Such as name BEGINSWITH ‘J’ AND age >= 32
  • The containment operand IN such as name IN {‘Lisa’, ‘Spike’, ‘Hachi’}
  • Nil comparisons ==, !=, e.g. [Company objectsWhere:@”ceo == nil”]. Note this only works for objects with relationships, for example here, ceo is a property on the Company model.
  • ANY comparisons, such as ANY student.age < 21
  • Note, although there’s no support for the aggregate expression type, we do support the BETWEEN operator type using object values, e.g. RLMResults *results = [Person objectsWhere:@"age BETWEEN %@", @[42, 43]];

For more, see [RLMObject objectsWhere:].

Ordering Results

RLMResults allows you to specify a sort criteria and order based on a single or multiple properties. For example, the following calls [RLMObject objectsWhere:where:] to sort the returned dogs from the example above alphabetically by name:

// Sort tan dogs with names starting with "B" by name
RLMResults *sortedDogs = [[Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"]
                               sortedResultsUsingProperty:@"name" ascending:YES];
// Sort tan dogs with names starting with "B" by name
var sortedDogs = Dog.objectsWhere("color = 'tan' AND name BEGINSWITH 'B'").sortedResultsUsingProperty("name", ascending: true)

For more, see [RLMObject objectsWhere:] and [RLMResults sortedResultsUsingProperty:ascending:].

Chaining Queries

One unique property of Realm’s query engine is the ability to chain queries with very little transactional overhead when compared to traditional databases that require a separate trip to the database server for each successive query.

For example, if we wanted a result set for just the tan colored dogs, and the tan colored dogs whose names also started with ‘B’, you might chain two queries like this:

RLMResults *tanDogs = [Dog objectsWhere:@"color = 'tan'"];
RLMResults *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH 'B'"];
let tanDogs = Dog.objectsWhere("color = 'tan'")
let tanDogsWithBNames = tanDogs.objectsWhere("name BEGINSWITH 'B'")

Realms

The Default Realm

You may have noticed so far that we have always initialized access to our realm variable by calling [RLMRealm defaultRealm]. That method returns an RLMRealm object that maps to a file called “default.realm” under the Documents folder of your app.

Other Realms

It’s sometimes useful to have multiple Realms persisted at different locations. For example, if you need to bundle data with an application, you can open a second read-only Realm. See [RLMRealm realmWithPath:] and [RLMRealm realmWithPath:readOnly:error:] for more info.

Please note that the path passed to [RLMRealm realmWithPath:] must be in a location with write permissions. The most common location to store writable Realm files is the “Documents” directory on iOS and the “Application Support” directory on OSX.

Using a Realm Across Threads

To access the same Realm file from different threads, you must call [RLMRealm defaultRealm], [RLMRealm realmWithPath:] or [RLMRealm realmWithPath:readOnly:error:] to get a different Realm object for every thread of your app. As long as you specify the same path, all RLMRealm objects will map to the same file on disk. Sharing RLMRealm instances across threads is not supported.

In-Memory Realms

Normally Realms are persisted to disk, but you can also create ones which are purely in memory by using the [RLMRealm inMemoryRealmWithIdentifier:] factory method:

RLMRealm *realm = [RLMRealm inMemoryRealmWithIdentifier:@"MyInMemoryRealm"];
let realm = RLMRealm.inMemoryRealmWithIdentifier("MyInMemoryRealm")

In-memory Realms do not save data across app launches, but all other features of Realm will work as expected, including querying, relationships and thread-safety. This is a useful option if you need flexible data access without the overhead of disk persistence.

Notice: When all in-memory Realm instances with a particular identifier go out of scope with no references, all data is freed for that Realm. It is recommended that you hold onto a strong reference to any created in-memory Realms for the duration of your app.

Relationships

RLMObjects can be linked to each other by using RLMObject and RLMArray<Object> properties. RLMArrays have an interface very similar to NSArray and objects contained in an RLMArray can be accessed using indexed subscripting. Unlike NSArrays, RLMArrays are typed and only hold RLMObjects of a single subclass type. For more details see RLMArray.

Assuming your Person model has already been defined (see above) let’s create another model called Dog:

// Dog.h
@interface Dog : RLMObject
@property NSString *name;
@end
class Dog: RLMObject {
    dynamic var name = ""
}

To-One

For many-to-one or one-to-one relationships, simply declare a property with the type of your RLMObject subclass:

// Dog.h
@interface Dog : RLMObject
... // other property declarations
@property Person *owner;
@end
class Dog: RLMObject {
    ... // other property declarations
    dynamic var owner: Person?
}

You can use this property like you would any other:

Person *jim = [[Person alloc] init];
Dog    *rex = [[Dog alloc] init];
rex.owner = jim;
let jim = Person()
let rex = Dog()
rex.owner = jim

When using RLMObject properties, you can access nested properties using normal property syntax. For example rex.owner.address.country will traverse the object graph and automatically fetch each object from Realm as needed.

To-Many

You can define a to-many relationship using RLMArray<Object> properties. RLMArrays contain other RLMObjects of a single type and have an interface very similar to NSMutableArray.

To add a “dogs” property on our Person model that links to multiple dogs we must first define an RLMArray<Dog> type. This is done via a macro at the bottom of the corresponding model interface:

//Dog.h
@interface Dog : RLMObject
... // property declarations
@end

RLM_ARRAY_TYPE(Dog) // Defines an RLMArray<Dog> type
// Not needed in Swift

You can then declare properties of the RLMArray<Dog> type:

// Person.h
@interface Person : RLMObject
... // other property declarations
@property RLMArray<Dog> *dogs;
@end
class Person: RLMObject {
    ... // other property declarations
    dynamic var dogs = RLMArray(objectClassName: Dog.className())
}

You can access and assign RLMArray properties as usual:

// Jim is owner of Rex and all dogs named "Fido"
RLMArray *someDogs = [Dog objectsWhere:@"name contains 'Fido'"];
[jim.dogs addObjects:someDogs];
[jim.dogs addObject:rex];
let someDogs = Dog.objectsWhere("name contains 'Fido'")
jim.dogs.addObjects(someDogs)
jim.dogs.addObject(rex)

Notifications

Realm instances send out notifications to other instances on other threads every time a write transaction is committed. These notifications can be observed by registering a block:

// Observe Realm Notifications
self.token = [realm addNotificationBlock:^(NSString *note, RLMRealm * realm) {
    [myViewController updateUI];
}];
// Observe Realm Notifications
let token = realm.addNotificationBlock { note, realm in
    viewController.updateUI()
}

The notification stays active as long as a reference is held to the returned notification token. You should hold onto a strong reference to this token on the class registering for updates, as notifications are automatically un-registered when the notification token is deallocated.

See [Realm addNotificationBlock:] and [Realm removeNotificationBlock:] for details.

Background Operations

Realm can be very efficient when writing large amounts of data by batching together multiple writes within a single transaction. Transactions can also be performed in the background using Grand Central Dispatch to avoid blocking the main thread. RLMRealm objects are not thread safe and cannot be shared across threads, so you must get an RLMRealm instance in each thread/dispatch_queue in which you want to read or write. Here’s an example of inserting a million objects in a background queue:

dispatch_async(queue, ^{    
    
  // Get realm and table instances for this thread
  RLMRealm *realm = [RLMRealm defaultRealm];
  
  // Break up the writing blocks into smaller portions
  // by starting a new transaction
  for (NSInteger idx1 = 0; idx1 < 1000; idx1++) {
    [realm beginWriteTransaction];
    
    // Add row via dictionary. Property order is ignored.
    for (NSInteger idx2 = 0; idx2 < 1000; idx2++) {
      [Person createInRealm:realm
                 withObject:@{@"name"      : [self randomString],
                              @"birthdate" : [self randomDate]}];
    }

    // Commit the write transaction
    // to make this data available to other threads
    [realm commitWriteTransaction];
  }
});
dispatch_async(queue) {
  // Get realm and table instances for this thread
  let realm = RLMRealm.defaultRealm()

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

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

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

See RLMRealm for more details.

REST APIs

Realm easily integrates with REST APIs and provides several advantages as oppposed to using REST APIs without local persistance:

  • Caching your data in Realm allows you to provide an offline experience, as opposed to REST APIs where connectivity is always required.
  • By caching your entire data set in Realm, you can exectute queries locally and provide a better search and browsing experience than wouldn’t be possible with REST alone.
  • Storing your data in Realm can reduce server-side load by only fetching new or changed data.

Best Practices

  1. Asynchronous Requests — Network requests and other blocking operations should be performed on a background thread to avoid blocking the user interface. For the same reason it is recommended that inserting or changing a large number of objects in a Realm are made on a background thread. You can use Notifications to respond to changes made in the background.
  2. Caching large datasets — We recommend you pre-fetch data when possible and store it locally in a Realm. This allows you to perform queries over your entire dataset locally.
  3. Insert-or-update — If your dataset has a unique identifier, such as a primary key, you can use it to easily implement insert-or-update logic using [RLMObject createOrUpdateInDefaultRealmWithObject:]: when receiving a response from a REST API. These methods automatically check if each record already exist and apply updates to existing records while creating new records.

Example

The following is a simple example of how you can use Realm with a REST API. In this example, we’ll retrieve a JSON-formatted data set from the foursquare API, then save it as Realm Objects in the default Realm.

For a realtime example of a similar use case in action, check out our video demo.

First we create an instance of the default Realm to persist the data to, and fetch our data set from the API. For simplicity in this example we use [NSData initWithContentsOfURL].

// Call the API
NSData *response = [[NSData alloc] initWithContentsOfURL:
                    [NSURL URLWithString:@"https://api.foursquare.com/v2/venues/search?near=San%20Francisco&limit=50"]];

// Deserialize the response to JSON
NSDictionary *json = [[NSJSONSerialization
                       JSONObjectWithData:response
                                  options:kNilOptions
                                    error:&error] objectForKey:@"response"];
// Call the API
let url = NSURL(string: "https://api.foursquare.com/v2/venues/search?near=San%20Francisco&limit=50")
let response = NSData(contentsOfURL: url)

// De-serialize the response to JSON
let json = NSJSONSerialization.JSONObjectWithData(response,
    options: NSJSONReadingOptions(0),
      error: nil)["response"]

The response contains a JSON array of venues similar to this:

{
  "venues": [
    {
      "id": "4c82f252d92ea09323185072",
      "name": "Golden Gate Park",
      "contact": {
        "phone": "4152522590"
      },
      "location": {
        "lat": 37.773835608329,
        "lng": -122.41962432861,
        "postalCode": "94103",
        "cc": "US",
        "state": "California",
        "country": "United States"          
      }
    }
  ]
}

There are several ways we may want to import this JSON into our Realm. You could read the NSDictionary and map the properties to a single RLMObject manually via a custom insert function. For the sake of this example, we will instead directly insert the NSDictionary in the Realm and have it automatically be mapped to a hierarchy of RLMObjects that will be created on the fly for us. For this to work, we need an RLMObject structure whose properties will match all the keys in the JSON exactly. JSON keys not matched by an RLMObject property will be ignored on insert. The following RLMObject declarations would work:

// Contact.h
@interface Contact : RLMObject
@property NSString *phone;
@end

@implementation Contact
+ (NSString)primaryKey {
    return @"phone";
}
@end
RLM_ARRAY_TYPE(Contact)

// Location.h
@interface Location : RLMObject
@property double lat; // latitude
@property double lng; // longitude
@property NSString *postalCode;
@property NSString *cc;
@property NSString *state;
@property NSString *country;
@end

@implementation Location
@end
RLM_ARRAY_TYPE(Location)

// Venue.h
@interface Venue : RLMObject
@property NSString *id;
@property NSString *name;
@property Contact  *contact;
@property Location *location;
@end

@implementation Venue
+ (NSString)primaryKey {
    return @"id";
}
@end
RLM_ARRAY_TYPE(Venue)
class Contact: RLMObject {
    dynamic var phone = ""

    class func primaryKey() -> String! {
        return "phone"
    }
}

class Location: RLMObject {
    dynamic var lat = 0.0  // latitude
    dynamic var lng = 0.0  // longitude
    dynamic var postalCode = ""
    dynamic var cc = ""
    dynamic var state = ""
    dynamic var country = ""
}

class Venue: RLMObject {
    dynamic var id = ""
    dynamic var name = ""
    dynamic var contact = Contact()
    dynamic var location = Location()

    class func primaryKey() -> String! {
        return "id"
    }
}

Since the result set is given to us as an array we have to create an object for each element by calling [Venue createInDefaultRealmWithObject:]. This creates Venue and its child objects from a JSON representation and adds the newly created obejcts to the default Realm:

//Extract the array of venues from the response
NSArray *venues = json[@"venues"];

RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
// Save one Venue object (and dependents) for each element of the array
for (NSDictionary *venue in venues) {
    [Venue createOrUpdateInDefaultRealmWithObject:venue];
}
[realm commitWriteTransaction];
//Extract the array of venues from the response
let venues = json["venues"] as [NSDictionary]

let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
// Save one Venue object (and dependents) for each element of the array
for venue in venues {
    Venue.createOrUpdateInDefaultRealmWithObject(venue)
}
realm.commitWriteTransaction()

Migrations

When working with any database, it is likely your data model will change over time. Since data models in Realm are defined as standard Objective‑C interfaces, making model changes is as easy as changing any other Objective‑C interface. For example, suppose we have the following interface in ‘Person.h’:

@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end
class Person: RLMObject {
    dynamic var firstName = ""
    dynamic var lastName = ""
    dynamic var age = 0
}

We want to update the data model to require a ‘fullName’ property, rather than separate first and last names. To do this, we simply change the object interface to the following:

@interface Person : RLMObject
@property NSString *fullName;
@property int age;
@end
class Person: RLMObject {
    dynamic var fullName = ""
    dynamic var age = 0
}

At this point if you have saved any data, there will be a mismatch between what Realm sees defined in code and the data Realm sees on disk. When this occurs an exception will be thrown unless you run a migration.

Performing a Migration

You define a migration and the associated schema version by calling [RLMRealm setSchemaVersion:withMigrationBlock:]. Your migration block provides all the logic for converting data models from previous schemas to the new schema. After calling [RLMRealm setSchemaVersion:withMigrationBlock:], any Realms which require migration will automatically apply the migration block provided and be updated to the provided version.

For example, suppose we want to migrate the Person subclass from above. The minimal necessary migration block would be the following:

// Inside your [AppDelegate didFinishLaunchingWithOptions:]

// Notice setSchemaVersion is set to 1, this is always set manually. It must be
// higher than the previous version (oldSchemaVersion) or an RLMException is thrown
[RLMRealm setSchemaVersion:1
            forRealmAtPath:[RLMRealm defaultRealmPath] 
        withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) {
  // We haven’t migrated anything yet, so oldSchemaVersion == 0
  if (oldSchemaVersion < 1) {
    // Nothing to do!
    // Realm will automatically detect new properties and removed properties
    // And will update the schema on disk automatically
  }
}];

// now that we have called `setSchemaVersion:withMigrationBlock:`, opening an outdated
// Realm will automatically perform the migration and opening the Realm will succeed
[RLMRealm defaultRealm];
// Inside your application(application:didFinishLaunchingWithOptions:)

// Notice setSchemaVersion is set to 1, this is always set manually. It must be
// higher than the previous version (oldSchemaVersion) or an RLMException is thrown
RLMRealm.setSchemaVersion(1, forRealmAtPath: RLMRealm.defaultRealmPath(),
                         withMigrationBlock: { migration, oldSchemaVersion in
  // We haven’t migrated anything yet, so oldSchemaVersion == 0
  if oldSchemaVersion < 1 {
    // Nothing to do!
    // Realm will automatically detect new properties and removed properties
    // And will update the schema on disk automatically
  }
})
// now that we have called `setSchemaVersion:withMigrationBlock:`, opening an outdated
// Realm will automatically perform the migration and opening the Realm will succeed
// i.e. RLMRealm.defaultRealm()

At the very minimum all we need to do is to update the version with an empty block to indicate the that the schema has been upgraded (automatically) by Realm.

While this is the minimum acceptable migration, we probably want to use this block to populate any new properties (in this case “fullName”) with something meaningful. Within the migration block we can call [RLMMigration enumerateObjects:block:] to enumerate each Realm Object of a certain type, and apply any necessary migration logic. Notice how for each enumeration the existing RLMObject instance is accessed via an oldObject variable and the updated instance is accessed via newObject:

// Inside your [AppDelegate didFinishLaunchingWithOptions:]

[RLMRealm setSchemaVersion:1 
            forRealmAtPath:[RLMRealm defaultRealmPath] 
        withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) {
  // We haven’t migrated anything yet, so oldSchemaVersion == 0
  if (oldSchemaVersion < 1) {
    // The enumerateObjects:block: method iterates
    // over every 'Person' object stored in the Realm file
    [migration enumerateObjects:Person.className
                          block:^(RLMObject *oldObject, RLMObject *newObject) {    
      
      // combine name fields into a single field
      newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
                                         oldObject[@"firstName"],
                                         oldObject[@"lastName"]];          
    }];
  }
}];
// Inside your application(application:didFinishLaunchingWithOptions:)

RLMRealm.setSchemaVersion(1, forRealmAtPath: RLMRealm.defaultRealmPath(),
                         withMigrationBlock: { migration, oldSchemaVersion in
  if oldSchemaVersion < 1 {
    // The enumerateObjects:block: method iterates
    // over every 'Person' object stored in the Realm file
    migration.enumerateObjects(Person.className()) { oldObject, newObject in
      // combine name fields into a single field
      let firstName = oldObject["firstName"] as String
      let lastName = oldObject["lastName"] as String
      newObject["fullName"] = "\(firstName) \(lastName)"
    }
  }
})

Once the migration is successfully completed, the Realm and all of its Objects can be accessed as usual by your app.

Adding more versions

Suppose now we have two previous versions of the Person class:

// v0
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end

// v1
@interface Person : RLMObject
@property NSString *fullName; // new property
@property int age;
@end

// v2
@interface Person : RLMObject
@property NSString *fullName;
@property NSString *email;   // new property
@property int age;
@end
// v0
class Person: RLMObject {
    dynamic var firstName = ""
    dynamic var firstName = ""
    dynamic var age = 0
}

// v1
class Person: RLMObject {
    dynamic var fullName = "" // new property
    dynamic var age = 0
}

// v2
class Person: RLMObject {
    dynamic var fullName = ""
    dynamic var email = "" // new property
    dynamic var age = 0
}

The logic in our migration block might look like the following.

[RLMRealm setSchemaVersion:2 forRealmAtPath:[RLMRealm defaultRealmPath] 
                         withMigrationBlock:^(RLMMigration *migration, 
                                              NSUInteger oldSchemaVersion) {
  // The enumerateObjects:block: method iterates
  // over every 'Person' object stored in the Realm file
  [migration enumerateObjects:Person.className 
                        block:^(RLMObject *oldObject, RLMObject *newObject) {
    // Add the 'fullName' property only to Realms with a schema version of 0
    if (oldSchemaVersion < 1) {
      newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
                                oldObject[@"firstName"],
                                oldObject[@"lastName"]];
    }

    // Add the 'email' property to Realms with a schema version of 0 or 1
    if (oldSchemaVersion < 2) {
      newObject[@"email"] = @"";
    }
  }];
}];

// now that we have called `setSchemaVersion:withMigrationBlock:`, opening an outdated
// Realm will automatically perform the migration and opening the Realm will succeed
[RLMRealm defaultRealm];
RLMRealm.setSchemaVersion(2, forRealmAtPath: RLMRealm.defaultRealmPath(), 
                         withMigrationBlock: { migration, oldSchemaVersion in
  // The enumerateObjects:block: method iterates
  // over every 'Person' object stored in the Realm file
  migration.enumerateObjects(Person.className()) { oldObject, newObject in
    // Add the 'fullName' property only to Realms with a schema version of 0
    if oldSchemaVersion < 1 {
      let firstName = oldObject["firstName"] as String
      let lastName = oldObject["lastName"] as String
      newObject["fullName"] = "\(firstName) \(lastName)"
    }

    // Add the 'email' property to Realms with a schema version of 0 or 1
    if oldSchemaVersion < 2 {
        newObject["email"] = ""
    }
  }
})

// Realm will automatically perform the migration and opening the Realm will succeed
let realm = RLMRealm.defaultRealm()

For a more complete look at the implementation of a data schema migration, check out our migration sample app.

Linear Migrations

Suppose we have two users for our app: JP and Tim. JP updates the app very often, but Tim happens to skip a few versions. It’s likely that JP has seen every new version of our app, and every schema upgrade in sequence: he downloaded a version of the app that took him from v0 to v1, another update that took him from v1 to v2. In contrast, it’s possible that Tim will download an update of the app that would need to take him from v0 to v2 immediately. Structuring your migration blocks with non-nested if (oldSchemaVersion < X) calls ensures that they will see all necessary upgrades, no matter which schema version they start from.

Another scenario may arise in the case of users who skipped versions of your app. If you delete a property “email” at version 2 and re-introduce it at version 3, and a user jumps from version 1 to version 3, Realm will not be able to automatically detect the deletion of the “email” property, as there will be no mismatch between the schema on disk and the schema in the code for that property. This will lead to Tim’s Person object having a v3 address property that has the contents of the v1 address property. This may not be a problem, unless you changed the internal storage representation of that property between v1 and v3 (say, went from an ISO address representation to a custom one). To avoid this, we recommend you nil out the “email” property on the if (oldSchemaVersion < 3) statement, guaranteeing that all realms upgraded to version 3 will have a correct dataset.

Next Steps

You can look at our examples to see Realm used in practice in an app. (We’re getting more samples ready!)

Happy hacking! You can always talk to a live human developer on realm-cocoa.

Current Limitations

Realm is currently in beta and we are continuously adding features and fixing issues while working towards a 1.0 release. Until then, we’ve compiled a list of our most commonly hit limitations.

Please refer to our GitHub issues for a more comprehensive list of known issues.

Realm in CocoaPods does not work for Swift projects

CocoaPods doesn’t support Swift projects yet (see their GitHub issue #2222). To use Realm in a Swift project, please follow the instructions above.

Fine-grained notifications are not yet supported

While it is possible to receive notifications when a realm changes (see Notifications), it is not currently possible to determine what was added/removed/moved/updated from that notification. We will be adding this feature in the near future.

NSDate is truncated to the second

Persisting an NSDate with a fractional number of seconds will truncate the date to the second. A fix for this is in progress. See GitHub issue #875 for more details. In the mean time, you can store NSTimeInterval properties with no loss in precision.

Realm Object Setters & Getters cannot be overriden

Since Realm overrides setters and getters to back properties directly by the underlying database, you cannot override them on your objects. A simple workaround is to create new, realm-ignored properties, whose accessors can be overriden, and can call other setters/getters.

KVO is not supported

Realm doesn’t support KVO but has its own notification mechanism (see Notifications).

Realm files cannot be accessed by concurrent processes

Although Realm files can be accessed by multiple threads concurrently, they can only be accessed by a single process at a time. This has implications for iOS 8 extensions and OSX applications. Different processes should either copy Realm files or create their own. Multi-process support is forthcoming.

FAQ

How big is the Realm library?

Once your app is built for release, Realm should only add around 1MB to its size. The releases we distribute are significantly larger (~37MB for iOS & ~2.4MB for OSX) because they include support for more architectures (ARM, ARM64, x86 for the simulator) and some debug symbols, which will all be stripped by Xcode automatically when you build your app.

Should I use Realm in production applications?

Realm has been used in production in commercial products since 2012.

You should expect our Objective‑C & Swift APIs to change as we evolve the product from community feedback — and you should expect more features & bugfixes to come along as well.

How can I protect data stored in Realm?

There are several ways to encrypt data in tandem with Realm, each with their own set of tradeoffs. See this GitHub comment for an overview of options. Cross-platform encryption support in Realm will come in a future release.

Do I have to pay to use Realm?

No, Realm is entirely free to use, even in commercial projects.

How do you all plan on making money?

We’re actually already generating revenue selling enterprise products and services around our technology. If you need more than what is currently in our releases or in realm-cocoa, we’re always happy to chat by email. Otherwise, we are committed to developing realm-cocoa in the open, and to keep it free and open-source under the Apache 2.0 license.

I see references to “tightdb” or a “core” in the code, what is that?

TightDB is the old name of our core C++ storage engine. The core is not currently open-source but we do plan on open-sourcing it, also under the Apache 2.0 license, once we’ve had a chance to clean it, rename it and finalize our synchronization implementation inside of it. In the meantime, its binary releases are made available under the Realm Core (TightDB) Binary License.