Realm Cocoa 0.85

We just pushed a Realm Objective-C update to this website and to CocoaPods. Here’s what’s new!

Primary Keys

Realm now supports marking a single string or int property on an object as the primary key. Primary keys are checked for uniqueness, and several new methods have been added which create a new object in a Realm if no object with the given primary key exists already, or updates the existing object if one does (aka upserting). This even works for nested objects, which means that you can pass decoded JSON from a server containing nested objects to Realm to painlessly update an entire tree of objects in a single shot. For example, given the following model definitions:

@interface Dog : RLMObject
@property int key;
@property NSString *name;
@property NSInteger age;
@end

@implementation Dog : RLMObject
+ (NSString *)primaryKey {
    return @"key";
}
@end

RLM_ARRAY_TYPE(Dog)

@interface Owner : RLMObject
@property int key;
@property NSString *name;
@property RLMArray<Dog> *dogs;
@end

@implementation Owner : RLMObject
+ (NSString *)primaryKey {
    return @"key";
}
@end

When you get your initial set of data, you could do something like the following. This would result in a new Owner and a new Dog being created, as neither of the objects already exist in the Realm.

Owner *owner = [Owner createOrUpdateInDefaultRealmWithObject:@{
    @"key": @0,
    @"name": @"Tim",
    @"dogs": @[
        @{@"key": @5, @"name": @"Rex", @"age": @3}
    ]
}];

NSLog(@"Number of owners: %u", (unsigned)[Owner allObjects].count);
NSLog(@"Number of dogs: %u", (unsigned)owner.dogs.count);
for (Dog *dog in owner.dogs) {
    NSLog(@"Dog %@", dog);
}

Later on when you get an updated set of data, you’d pass it to the same function. The current Dog object has its age updated, while the new Dog is created and added to the existing Owner’s array of dogs.

[Owner createOrUpdateInDefaultRealmWithObject:@{
    @"key": @0,
    @"name": @"Tim",
    @"dogs": @[
        @{@"key": @5, @"name": @"Rex", @"age": @4},
        @{@"key": @6, @"name": @"Rover", @"age": @1}
    ]
}];

NSLog(@"Number of owners: %u", (unsigned)[Owner allObjects].count);
NSLog(@"Number of dogs: %u", (unsigned)owner.dogs.count);
for (Dog *dog in owner.dogs) {
    NSLog(@"Dog %@", dog);
}

In addition to being far less code than manually checking if the object already exists, this is also quite a bit faster.

-[RLMObject isEqual:] and -[RLMObject hash] now use the primary key to determine equality when possible, which means that objects with primary keys can be used as the key for an NSDictionary or added to an NSSet. When no primary key is available, isEqual: now uses the default pointer equality. Use isEqualToObject: for the old behavior of checking whether the two objects refer to the same row in the database.

Once set, primary keys can only be changed during a schema migration.

Swift Fixes

Several Swift-related things have been fixed:

  1. Optional RLMObject properties are now supported (although they still need a non-nil default).
  2. Int64 properties now work property on 32-bit devices.
  3. The Swift support code has been mostly rewritten in Objective-C, as it turns out that iTunesConnect does not allow Swift in Frameworks when targeting iOS 7.0. There is now a single file (RLMSupport.swift) which must be added to your application’s target when using Realm and Swift together, for the bits that we couldn’t write in Objective-C.

Xcode 6 GM is now supported, as are betas 5 and up.

Read-only Realm files

Read-only files shipped in your application bundle can now be opened with [RLMRealm realmWithPath:path readOnly:YES error:&error], rather than having to first copy them to a writable location. readOnly:YES should only be used for files which actually are read-only: it disables Realm’s change tracking mechanisms, so modifying a file while a read-only Realm is accessing it will lead to problems.

Query Improvements

Getting just the number of items in a query (e.g. [Dog objectsWhere:@"age > 5"].count) now does even less unnecessary work, making it typically about twice as fast. Performance of sorting queries has been improved similarly, and a crash has been fixed.

Notification Improvements

When autorefresh is disabled, RLMRealmRefreshRequiredNotification is now sent when a write transaction is committed on a different thread. In addition, RLMRealmDidChangeNotification is now always sent after the change has been applied, rather than occasionally before, and -[RLMRealm refresh] has a return value that indicates whether or not a change was made.

Update Checker

Realm now automatically checks for updates when running in a simulator, and logs a message if there is a new version available. This can be disabled by setting the environment variable REALM_DISABLE_UPDATE_CHECKER in your debug settings.