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)

Select “iOS” from the list of targets

Expand “Link Binary with Libraries” and click on the + and select Realm.framework (iOS)

Click on the + in the upper left to add a “New Copy Files Phase”

In the new “Copy Files Phase”, change the destination from “Resources” to “Frameworks”

Click on the + in the “Copy Files Phase” and select Realm.framework

Xcode will have automatically added both the OSX and iOS versions of Realm. Delete the one that does not say “iphoneos”

Set “Defines Module” to YES.

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

Sign up for our community newsletter to get regular tips, learn about other use-cases and get alerted of blogposts and tutorials about Realm.

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.

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 a Person objectletauthor=Person()author.name="David Foster Wallace"// Get the default Realmletrealm=RLMRealm.defaultRealm()// Add to the Realm inside a transactionrealm.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!

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=[DogallObjects];// retrieves all Dogs from the default Realm
// On a specific Realm
RLMRealm*petsRealm=[RLMRealmrealmWithPath:@"pets.realm"];// get a specific Realm
RLMArray*otherDogs=[DogallObjectsInRealm:petsRealm];//retrieveallDogsfromthatRealm

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=[DogobjectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];// … Or using an NSPredicate object
NSPredicate*pred=[NSPredicatepredicateWithFormat:@"color = %@ AND name BEGINSWITH %@",@"tan",@"B"];RLMArray*tanDogs2=[DogobjectsWithPredicate:pred];

// Query using a predicate string:lettanDogs=Dog.objectsWhere("color = 'tan' AND name BEGINSWITH 'B'")// Query using an NSPredicate object:letpredicate=NSPredicate(format:"color = %@ AND name BEGINSWITH %@","tan","B")lettanDogs2=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.

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

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=[[DogobjectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"]arraySortedByProperty:@"name"ascending:YES];

// Using a string (sort is ascending by default)varsortedDogs=Dog.objectsWhere("color = 'tan' AND name BEGINSWITH 'B'").arraySortedByProperty("name",ascending:true)

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:

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

// You must call this method before accessing the default RealmRLMRealm.useInMemoryDefaultRealm()letrealm=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
@interfaceDog:RLMObject@propertyNSString*name;@end

classDog:RLMObject{varname=""}

Many-to-One

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

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:

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:

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.

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=[RLMRealmdefaultRealm];// Break up the writing blocks into smaller portions
// by starting a new transaction
for(NSIntegeridx1=0;idx1<1000;idx1++){[realmbeginWriteTransaction];// Add row via dictionary. Order is ignored.
for(NSIntegeridx2=0;idx2<1000;idx2++){[PersoncreateInRealm:realmwithObject:@{@"name":[selfrandomString],@"birthdate":[selfrandomDate]}];}// Commit the write transaction
// to make this data available to other threads
[realmcommitWriteTransaction];}});

dispatch_async(queue){// Get realm and table instances for this threadletrealm=RLMRealm.defaultRealm()// Break up the writing blocks into smaller portions// by starting a new transactionforidx1in0..<1000{realm.beginWriteTransaction()// Add row via dictionary. Order is ignored.foridx2in0..<1000{Person.createInDefaultRealmWithObject(["name":"\(idx1)","birthdate":NSDate(timeIntervalSince1970:idx2)])}// Commit the write transaction// to make this data available to other threadsrealm.commitWriteTransaction()}}

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

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.

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

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

// Call the APIleturl=NSURL(string:"https://api.foursquare.com/v2/venues/search?near=San%20Francisco&limit=50")letresponse=NSData(contentsOfURL:url)// De-serialize the response to JSONletjson=NSJSONSerialization.JSONObjectWithData(response,options:NSJSONReadingOptions(0),error:nil)["response"]

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:

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"];[realmbeginWriteTransaction];// Save one Venue object (and dependents) for each element of the array
for(NSDictionary*venueinvenues){[VenuecreateInDefaultRealmWithObject:venue];}[realmcommitWriteTransaction];

//Extract the array of venues from the responseletvenues=json["venues"]as[NSDictionary]realm.beginWriteTransaction()// Save one Venue object (and dependents) for each element of the arrayforvenueinvenues{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’:

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

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:]
RLMMigrationBlockmigrationBlock=^NSUInteger(RLMMigration*migration,NSUIntegeroldSchemaVersion){// 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
return1;};// Apply the migration block above to the default Realm
[RLMRealmmigrateDefaultRealmWithBlock: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
[RLMRealmmigrateDefaultRealmWithBlock:^NSUInteger(RLMMigration*migration,NSUIntegeroldSchemaVersion){// 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
[migrationenumerateObjects:Person.classNameblock:^(RLMObject*oldObject,RLMObject*newObject){// Update each individual 'Person' object on disk using this logic:
newObject[@"fullName"]=[NSStringstringWithFormat:@"%@ %@",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
return1;}];

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

[RLMRealmmigrateDefaultRealmWithBlock:^NSUInteger(RLMMigration*migration,NSUIntegeroldSchemaVersion){// 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
[migrationenumerateObjects:Person.classNameblock:^(RLMObject*oldObject,RLMObject*newObject){// Add the 'fullName' property only to Realms with a schema version of 0
if(oldSchemaVersion<1){newObject[@"fullName"]=[NSStringstringWithFormat:@"%@ %@",oldObject[@"firstName"],oldObject[@"lastName"]];}// Add the 'email' property to Realms with a schema version of 0 or 1
if(oldSchemaVersion<2){newObject[@"email"]=[[NSStringalloc]init];}}];}// Return the latest version number (always set manually)
// Must be a higher than the previous version or an RLMException is thrown
return2;}];

// 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-nestedif (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.