You are reading the documentation for an older version of Realm. You can view the latest documentation instead.

Getting Started

Manual installation

  1. Download the latest release of Realm and extract the zip.
  2. Drag Realm.framework from our release and into the Frameworks folder in your project in Xcode. Make sure Copy items into destination group’s folder is selected and press Finish.
  3. Click on the project in the Xcode file explorer. Select your target and go to the Build Phases tab. Under Link Binary with Libraries press + and add libc++.dylib.

Installation via CocoaPods

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!
  1. Download the source at github.com/realm/realm-cocoa
  2. Drag Realm-Xcode6.xcodeproj into your Xcode project
  3. In “Build Phases” of your app target, expand “Target Dependencies” and click on the + (2) (click any of the images to get a large version)
  4. Select “iOS” from the list of targets
  5. Expand “Link Binary with Libraries” and click on the + and select Realm.framework (iOS)
  6. Click on the + in the upper left to add a “New Copy Files Phase”
  7. In the new “Copy Files Phase”, change the destination from “Resources” to “Frameworks”
  8. Click on the + in the “Copy Files Phase” and select Realm.framework
  9. Xcode will have automatically added both the OSX and iOS versions of Realm. Delete the one that does not say “iphoneos”
  10. Set “Defines Module” to YES.
  11. Build and Run

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 dummy data using the menu item Tools > Generate demo database.

If you have installed Xcode 6 beta or are running Yosemite, you may get an “unidentified developer” error when launching the app due to a bug in Apple’s beta releases.
In that case, right click the app and select “Open”. You will still get a warning, but it will have a button to open the app anyway. Subsequent double-clicks will not show a warning at all. (Thanks for the tip @apalancat!)

Examples

You can find example Objective‑C applications in our release zip under examples/, demonstrating how to use many features of Realm like migrations, use in UITableViewController’s, encryption and much more.

Getting Help

Models

Realm data models are defined using traditional NSObject-style classes with @properties. Simply subclass RLMObject to create your Realm data model objects. Apart from the fact that they can be added to a Realm for persistence and sharing between threads, Realm model objects 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 only restriction is that objects can be used only on the thread on which they were created.

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 RLMArray’s for typed lists of objects.

@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
// Dog model
class Dog: RLMObject {
    var name = ""
    var owner = Person()
}

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

See RLMObject for more details.

Property Attributes

Note that Realm ignores Objective‑C property attributes like nonatomic, atomic, strong, copy, weak, etc. This is done because Realm has its own optimized storage semantics under the hood. So to avoid being misleading, we recommend writing models without any property attributes at all. However, if you do set property attributes, they will be used until an RLMObject is added to a realm.

Writes

All changes to an object (addition, edition and deletion) have to be done through write transactions.

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 add and retrieve them from a Realm. You can use transactions like so:

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

// Get the default Realm
RLMRealm *realm = [RLMRealm defaultRealm];

// 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()

// 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 from now on will be persisted and available from other threads that uses the same realm.

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

Please note that thanks to Realm’s MVCC architecture, reads are not blocked while a write transaction is open!

See RLMRealm and RLMObject for more details.

Queries

A note about using Realm Arrays (RLMArray): All successful calls to retrieval and querying methods return the resulting collection of RLMObjects in an RLMArray. RLMArrays can be manipulated similarly to a standard NSArray; however, RLMArrays are typed, meaning they only hold RLMObjects of the same RLMObject subclass type. For more details see RLMArray.

Retrieving Objects by Type

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

// On the default Realm:
RLMArray *dogs = [Dog allObjects]; // retrieves all Dogs from the default Realm

// On a specific Realm
RLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // get a specific Realm
RLMArray *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.realmWithPath("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 and RLMArray 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 with an NSObject instance.

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:

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

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

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

See Apple’s Predicates Programming Guide for more information about building predicates. Here are some details about our Predicates implementation:

  • 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.
  • The comparison operators == and != are supported for bool properties.
  • For NSString and NSData properties, we support the ==, !=, BEGINSWITH, CONTAINS, and ENDSWITH operators.
  • Realm supports the following compound operators: “AND”, “OR”, and “NOT”.
  • Note, although there’s no support for the aggregate expression type, we do support the BETWEEN operator type using object values, e.g. RLMArray *results = [Person objectsWhere:@"age BETWEEN %@", @[42, 43]];

For more, see [RLMObject objectsWhere:].

Ordering Results

In many cases it is desirable to be able to have a retrieval or query operation return an ordered result set. To enable this, RLMArray supports method that allow you to specify a property name to order the result set by.

For example, the following calls [RLMObject objectsWhere:where:] to sort the returned dogs from the example above alphabetically by name:

// Using a string (sort is ascending by default)
RLMArray *sortedDogs = [[Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"]
                    arraySortedByProperty:@"name" ascending:YES];
// Using a string (sort is ascending by default)
var sortedDogs = Dog.objectsWhere("color = 'tan' AND name BEGINSWITH 'B'").arraySortedByProperty("name", ascending: true)

For more, see [RLMObject objectsWhere:] and [RLMArray arraySortedByProperty:ascending:].

Chaining Queries

Another advantage of Realm’s use of regular objects to store your application data is the ability to chain queries with very little transactional overhead, 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:

RLMArray *tanDogs = [Dog objectsWhere:@"color = 'tan'"];
RLMArray *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. Write transactions will be automatically written to disk at that location for you, and likewise for reads.

In-Memory Default Realm

The Default Realm is persisted to disk by default, but you can also use it purely in memory by calling the following line before any call to [RLMRealm defaultRealm].

[RLMRealm useInMemoryDefaultRealm]; 
RLMRealm *realm = [RLMRealm defaultRealm]; // Only call this line after!
// You must call this method before accessing the default Realm
RLMRealm.useInMemoryDefaultRealm()
let realm = RLMRealm.defaultRealm()

This option is only available on the default Realm.

If you use your default Realm in memory, it will not persist your RLMObjects, meaning data will not be saved across app launches. However, 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.

Other Realms

It’s sometimes useful to have multiple realms, persisted at different locations, for example if you have different data groupings, different databases per feature, or you need to package some read-only files with your app, separate from the database your users will be editing. See [RLMRealm realmWithPath:] and [RLMRealm realmWithPath:readOnly:error:] for more info.

Using a Realm Across Threads

If you are trying to access the same realm file from different threads, you should 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.
Do not share RLMRealm objects across threads. It’s totally fine to have many RLMRealm objects, all mapping to the same file. You can even have multiple RLMRealm objects pointing to the same file living on the same thread.

Relationships

Any two RLMObjects can be linked together. 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 {
    var name = ""
}

Many-to-One

Simply declare a property with the type of one of your RLMObject subclasses:

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

This will create a property with name owner and type Person. You can assign and read it just like you would any other property:

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

When you do queries, children will not be fetched into memory at query time, but you will be able to navigate the links automatically without having to manually fetch children, i.e. doing calls such as rex.owner.address.country will automatically traverse the object graph for you to return the objects needed.

Many-to-Many

You can establish a relationship to several objects from a single object via an RLMArray<Object> property declaration. RLMArrays are basically containers of RLMObjects, that behave very much like an NSArray, with the notable exception that they are typed.

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
    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 addObjectsFromArray:someDogs];
[jim.dogs addObject:rex];
let someDogs = Dog.objectsWhere("name contains 'Fido'")
jim.dogs.addObjectsFromArray(someDogs)
jim.dogs.addObject(rex)

Note: RLMArray properties on models are “copy on write”. Any direct assignment of that property will copy the references to the objects from the assignee into the assigned property. In the example above, that means that any dogs added to some_dogs after jim.dogs = some_dogs; would not also be added to jim.dogs.

Notifications

The auto-updating Realm will send out notifications every time the underlying Realm is updated. These notifications can be observed by registering a block:

// Observe Realm Notifications

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

You can use the token to unsubscribe from the notification later on. We recommend you store this token on your Main class, as losing reference to it will automatically unsubscribe you from the notification.

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. 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. 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

Due to Realm’s small memory footprint and fast object querying, you can retrieve and persist as much as ten times the data you might normally fetch from a REST API, then query it directly from a Realm. This has several advantages:

  • Retrieve large amounts of data with a single API call or by pre-fetching in the background, then persist it in the Realm.
  • Since Realm is thread-safe, you can easily asynchronize this task and update your views once the REST call has completed.
  • Query data directly from the Realm, rather than waiting for the API to process complex queries server side.
  • Offer a strong user experience while offline since you can cache large datasets that you can still query and update.
  • Reduce server-side load: while the first few interactions may generate more traffic than usual, having a cache dataset can help reduce server-side load over time by reducing the frequency at which have to fetch the same data over and over.

Best Practices

  1. Asynchronous Requests — Since Realm can hold a large amount of data in a small footprint, a good practice is to execute multiple API requests in the background to build a larger local data set. This creates a more seamless user experience in your app, as the user never experiences wait time for an API request to return on the main thread. You can use Notifications to monitor the progress of your REST requests.
  2. Caching datasets larger than what will be immediately displayed to the user — We recommend you pre-fetch data as often as possible and store it locally in your Realms. For example, if you are only displaying 10 results per page in a List View, fetch the next 3-4 pages of results if the user is likely to visit them. You should consider doing the same with map view (fetch results for the surrounding areas) or for your app in general (pre-fetch data for screens the user is likely to browse to during the normal course of his usage).
  3. Insert-or-update — If your dataset has a unique identifier such as a primary key (or set of unicity conditions), you can use it to easily code insert-or-update logic: when receiving a response from the API, you can check if each record already exists by querying the Realm for it. If it does exist locally, update with the latest details from the response, if not, insert it into the Realm.

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].

RLMRealm *realm = [RLMRealm defaultRealm];

// 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:

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

// Contact.h
@interface Contact : RLMObject
@property NSString *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
RLM_ARRAY_TYPE(Location)
class Contact: RLMObject {
    var phone = ""
}

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

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

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"];

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

realm.beginWriteTransaction()
// Save one Venue object (and dependents) for each element of the array
for venue in venues {
    Venue.createInDefaultRealmWithObject(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 Objects, changing them is as easy as changing the interface of the corresponding RLMObject subclass. 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 {
    var firstName = ""
    var lastName = ""
    var age = 0
}

Next, 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 subclass interface to the following:

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

Just changing your code to the new definition will work fine, if you have no data stored on disk under the old schema. But if you do, there will be a mismatch between what Realm sees defined in code, and the data Realm sees on disk. In short if you change your schema definition in one of your models and then instantiate a realm with [RLMRealm defaultRealm] (or a similar realm instantiation call), that call will throw an NSException with a message that you should run a migration.

Realms that contain at least one class that has been redefined must be migrated to the current schema before they can be accessed. To make this process easy, Realm provides specialized classes and methods for handling schema migration.

Migrating a Realm to a new schema takes just two steps, and must be done before anything else so we recommend you complete them from inside your [AppDelegate didFinishLaunchingWithOptions:]:

Performing a Migration

You define a migration by implementing an RLMMigrationBlock which you pass into a call to [RLMRealm migrateDefaultRealmWithBlock:] for the default Realm or [RLMRealm migrateRealmAtPath:withBlock:] for other Realm instances. Your migration block provides all the logic for converting data models from previous schemas to the new schema.

For example, suppose we want to migrate the ‘Person’ subclass from above. To do this, the minimal necessary migration block would look like the following:

// Inside your [AppDelegate didFinishLaunchingWithOptions:]

RLMMigrationBlock migrationBlock = ^NSUInteger(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
  }
  // Return the latest version number (always set manually)
  // Must be a higher than the previous version or an RLMException is thrown
  return 1;
};

// Apply the migration block above to the default Realm
[RLMRealm migrateDefaultRealmWithBlock:migrationBlock];
// Coming soon…

At the very minimum, all we need to do is return 1; to indicate the that the schema has been upgraded (automatically) by Realm.
N.B. The version number returned can be either an integer (version) or timestamp (epoch). We recommend you set it manually in the code as it defines the current version of the schema your app is using.
While you must manually return the version number to the app at the end of your migration block, note that Realm takes care of updating the schema version number inside the realm on disk.

While this is the minimal acceptable migration, we probably want to use this block to pre-fill the “fullName” property with something more 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:]

// Perform a migration defining the migration block inline
[RLMRealm migrateDefaultRealmWithBlock:^NSUInteger(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) {    
      
      // Update each individual 'Person' object on disk using this logic:
      newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
                                         oldObject[@"firstName"],
                                         oldObject[@"lastName"]];          
    }];
  }
  // Return the latest version number (always set manually)
  // Must be a higher than the previous version or an RLMException is thrown
  return 1;
}];
// Coming soon…

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 change the data model for the ‘Person’ subclass yet again, for a total of three different schemas:

// 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 {
    var firstName = ""
    var firstName = ""
    var age = 0
}

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

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

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

[RLMRealm migrateDefaultRealmWithBlock:^NSUInteger(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) {

            // 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"] = [[NSString alloc] init];
            }
        }];            }
    // Return the latest version number (always set manually)
    // Must be a higher than the previous version or an RLMException is thrown
    return 2;
}];
// Coming soon…

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 between sessions in. 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 “say address” 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 “address” 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 or the address 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.

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 (around 30MB for each .Framework) 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.

Can I use Realm for OS X?

Yes! At the moment you just need to build from source, which will create a separate, OS X compatible .Framework you can use in your apps. We are working on adding it to our CocoaPod as well.

Do I have to pay to use Realm?

No, Realm for iOS 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 once we’ve had a chance to clean it, rename it and finalize our synchronization implementation inside of it.