Realm Blog

Realm Java 0.88 — Better Objects!

by /

We just released a new version of Realm Java to this website and to Maven. This release includes many exciting new features.

Better Objects!

With this release, Realm for Android gives developers full control over their Realm objects. You will now be able to:

  • Add custom methods to your objects.
  • Implement interfaces.
  • Add custom logic to the getters and setters.
  • Name the accessors in any way you prefer.
  • Skip accessors altogether and make the fields public.
  • Write your own toString(), equals(), and hashCode() methods.
  • Combine Realm with Lombok.

This means that from now on, dealing with Realm objects will feel a lot more like handling normal POJOs.

In order to make this happen, we had to make Realm a Gradle plugin and not simply a library. As mentioned in a previous post this means that from now on you will have to change the way you associate Realm to your project in the build.gradle file.

buildscript {
 repositories {
    jcenter()
 }

 dependencies {
    classpath 'io.realm:realm-gradle-plugin:0.88.0'
 }
}

apply plugin: 'com.android.application'
apply plugin: 'realm-android'

This also means that from now on we will not support other build systems other than Gradle. If this seems unreasonable to you, we’ve already prepared two issues for you to vote on to re-introduce support for Maven and/or Ant.

Your opinion will lead our decision on whether and when we will implement Ant and Maven plugins.

Note that a few restrictions still apply to Realm objects:

  • Subclassing from anything but RealmObject is not allowed.
  • Fields are not allowed to be final, volatile, or transient.

Other Improvements

This release also brings a number of other improvements:

Breaking Changes 🚨

  • All notifications now use the Looper queue. Previously, when committing a transaction, all RealmChangeListeners on the same thread were triggered immediately. In order to make change listeners more predictable and consistent, they are now being delayed to the next Looper message.

  • All RxJava Observables now hold a reference to the Realm instance that created them. This means that a Realm file is now only fully closed when all Observables have been unsubscribed from. It also means that it is now possible to close a Realm instance using doOnUnsubscribe.

See the full changelog for all the details.


Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, and Twitter.

Read more

Introducing Realm React Native

by /

This post announced the launch of Realm React Native in Feb. 2016 – Since then we’ve released new features and made numerous updates. Check out the latest here in Docs.

Today at Facebook’s React.js Conference, we’re launching a new Realm mobile database built specifically for React Native. It offers easy object persistence and full query capabilities, with a performance profile that’s usually 2–10x faster than existing options.

Like the other editions of Realm, it is designed from the ground up to enable reactive app development, with live objects, change events, and support for unidirectional data flows.

Here’s how it looks:

const Realm = require('realm');

class Person {}
Person.schema = {
    name: 'Person',
    primaryKey: 'name',
    properties: {
        name: 'string',
        age: {type: 'int', default: 0},
    },
};

const realm = new Realm({schema: [Person]});

// Query
let people = realm.objects('Person', 'age >= 17');
people.length // => 0

// Write
realm.write(() => {
    savedPerson = realm.create('Person', {
        name: 'Hal Incandenza',
        age: 17,
    });
});

// Queries are updated in real-time
people.length // => 1

Realm is a database built from the ground up for the unique challenges of mobile app development, that runs directly inside phones, tablets or wearables. We launched for Java, Objective-C, & Swift in 2014, and are now used on hundreds of millions of devices today by appmakers including Starbucks, Cisco, Walmart, Google, Amazon, & eBay, plus many many others.

Today, we’re launching for React Native, Facebook’s JavaScript framework that lets developers write JS code that becomes native iOS & Android apps. (Note: Realm supports React Native, not the web framework React. We’re all in on mobile!)

Realm React Native brings the modern design & simplicity you expect from Realm, and will allow you to target both iOS and Android with the same codebase. Despite only launching to the public today, Realm React Native has already been used in production for over 2 months by TaskRabbit!

What is Realm

Realm is not an ORM, and is not built on top of SQLite. Instead we’ve built a full database for mobile app developers, one that uses native JavaScript objects that are dynamically mapped to a full, custom database engine (not just a key-value store). This allows us to provide a simple API while preserving performance. With Realm, you can model complex data, link objects in a graph, and compose advanced queries.

class Dog {}
Dog.schema = {
    name: 'Dog',
    properties: {
        name: 'string',
        age: 'int',
    }
};

let realm = new Realm({schema: [Dog]});

realm.write(() => {
    realm.create('Dog', { name: 'Rex', age: 3 });
});
// Basic query
let r = realm.objects('Dog').filtered('age < 8');

// Queries are chainable
let r2 = r.filtered('name contains "Rex"');
r2.length // => 1

realm.write(() => {
    realm.create('Dog', { name: 'Rex Maximus', age: 4 });
});

// Queries are updated in real-time
r2.length // => 2
class Person {}
Person.schema = {
    name: 'string',
    dogs: {type: 'list', objectType: 'Dog'},
};

let realm = new Realm({schema: [Dog, Person]});

realm.write(() => {
    let person = realm.create('Person', {
        name: 'Tim',
        dogs: [{name: 'rex', age: 3}],
    });
});

You can see more examples of how to use these APIs in the ReactExample app and in the JS test files.

Why use Realm?

Easy

Realm’s primary focus has always been ease of use, and as you can see from the samples above, Realm React Native is no different. After that, we’ve been working on some of the same advantages our other products are known for…

Fast

Realm’s ease of use doesn’t come at a performance cost. Because of its memory mapping, lazy loading, and custom storage engine, Realm is usually faster than SQLite or AsyncStorage despite offering a rich object-based API. Although we always recommend everyone test their own use-cases, we usually see huge speedups when porting code to Realm. See benchmark results below.

Cross-platform

Realm React Native’s API allows you to write your app once in JavaScript and target both iOS & Android, but the Realm file format is also completely cross-platform, allowing data to be shared across iOS & Android easily. For debugging, .realm files can be opened via the Realm Browser.

Advanced

Realm objects are always up-to-date with the underlying data, making it trivial to follow reactive patterns or a unidirectional data flow. You can link Realm objects in graphs, query any property combination via an expressive query language, and even easily integrate Realm data in React Native ListViews.

Trusted

Realm React Native is built on top of the same core as Realm Java, Objective-C, & Swift, which is trusted by hundreds of millions of people around the world, and used by e-commerce applications, banks, healthcare providers, and even governments. Realm React Native itself has been used by TaskRabbit in production since December 2015.

Community-driven

Realm React Native is built in the open on GitHub. Features are prioritized based on customer requests and we welcome contributions.

Supported

Realm prioritizes support & bugfixes above all else. You can get answers about your database directly from the people that build & maintain it, via Stack Overflow, GitHub or Twitter.

Tests conducted on February 19, 2016, using the latest versions available of Realm, React Native SQLite Storage for SQLite, and React Native Store for AsyncStorage. Measurements taken on an iPhone 6s running iOS 9.2.1 and a Nexus 9 running Android 5.0.1. Source.

What’s Next

Today’s release of Realm React Native is slightly less advanced than what Realm Java, Objective-C, & Swift currently offer, but it’s already trusted in production by appmakers like TaskRabbit. We’d love your feedback on what we can improve, and we’re particularly interested in bug reports or feature requests on our GitHub repository. Expect the API to improve significantly over the next few weeks, especially as we polish advanced features like migrations and queries.

If you are a fan of JavaScript but React Native is not your platform, note that we plan on adding support for Cordova/PhoneGap/Ionic, and Node.js (V8) compatibility in the future.

We can’t wait to see what you will build with Realm!

We’d like to thank TaskRabbit & the React Native team for their support. Realm React Native is much better because of their input, & we are honored to launch Realm React Native at React Conf 2016!

Read more

Realm featured on the Fragmented podcast

by /

Christian Melchior, of our Java team, was a guest on the latest episode of the Fragmented podcast to talk about the latest at Realm. Listen to the whole episode for more!

Realm was featured on the Fragmented podcast.

Thanks, Donn, for having Christian on!

Read more

Realm Objective-C & Swift 0.98

by /

We just released version 0.98 of Realm Objective-C and Realm Swift.

This release adds support for collection notifications, background queries, subqueries, indexing & performance improvements, bug fixes and more!

Collection Notifications

It’s now possible to register for notification blocks to be invoked whenever Realm collections are updated by calling their addNotificationBlock method.

Collection instances asynchronously invoke the block with the initial collection when registered, and then invoke it again after each write transaction which changes the collection or any items contained within it.

// Observe Results Notifications
let token = realm.objects(Person).filter("age > 5").addNotificationBlock { results, error in
    // results is identical to 'realm.objects(Person).filter("age > 5")'
    viewController.updateUI()
}

// later
token.stop()
// Observe RLMResults Notifications
self.token = [[Person objectsWhere:@"age > 5"] addNotificationBlock:^(RLMResults *results, NSError *error) {
    // results is identical to '[Person objectsWhere:@"age > 5"]'
    [myViewController updateUI];
}];

// later
[self.token stop];

See our docs on Notifications and the following API documentation for details:

Swift Objective-C
Realm.addNotificationBlock(_:) -[RLMRealm addNotificationBlock:]
AnyRealmCollection.​addNotificationBlock(_:) -[RLMCollection addNotificationBlock:]
Results.addNotificationBlock(_:) -[RLMResults addNotificationBlock:]
List.addNotificationBlock(_:) -[RLMArray addNotificationBlock:]
NotificationToken.stop() -[RLMNotificationToken stop]

This continues laying the foundation that was started with KVO support for more granular notifications. Expect more improvements in this area in the near future.

Background Queries

Working on collection notifications allowed us to improve the mechanism that kept results always “live”.

Once the query has been executed, or a notification block has been added, the Results is kept up to date with changes made in the Realm, with the query execution performed on a background thread when possible.

This change should automatically reduce work done on the main thread for apps using Results to directly back table views, which is a recommended design pattern.

Subqueries

Subqueries are now supported, enabling a whole new class of queries that were previously either impossible or inefficient to implement with Realm.

For example, here’s how you could previously model a query for companies with part time employees over 30 years old:

let partTimeOverThirty = realm.objects(Employee).filter("age > 30 AND fulltime = NO")
let companies = realm.objects(Company).filter("ANY employee IN %@", partTimeOverThirty)
RLMResults<Employee *> *partTimeOverThirty = [Employee objectsWhere:@"age > 30 AND fulltime = NO"];
RLMResults<Company *> *companies = [Company objectsWhere:@"ANY employee IN %@", partTimeOverThirty];

But this query is fairly expensive to compute and doesn’t correctly auto-update. It would also be much more complex to compare count against any value other than zero.

And now with subqueries:

let companies = realm.objects(Company).filter(
  "SUBQUERY(employees, $employee, $employee.age > 30 AND $employee.fulltime = NO)[email protected] > 0"
)
NSString *predicate = @"SUBQUERY(employees, $employee, $employee.age > 30 AND $employee.fulltime = NO)[email protected] > 0";
RLMResults<Company *> *companies = [Company objectsWhere:predicate];

However, the following limitations apply to subqueries in Realm:

  • @count is the only operator that may be applied to the SUBQUERY expression.
  • The SUBQUERY(…)[email protected] expression must be compared with a constant.
  • Correlated subqueries are not yet supported.

Indexing & Performance Improvements

It’s now possible to index BOOL/Bool and NSDate properties, as well as optional properties in Realm Swift.

Performance when deleting objects with one or more indexed properties was also greatly improved.

Breaking Changes

  • Realm Swift no longer supports Swift 1.2. The last release to support Swift 1.2 was 0.97.1.
  • +[RLMRealm realmWithPath:]/Realm.init(path:) now inherits from the default configuration.

Other Enhancements

Includes changes shipped in 0.97.1.

  • Swift: Added Error enum allowing to catch errors e.g. thrown on initializing RLMRealm/Realm instances.
  • Fail with RLMErrorFileNotFound instead of the more generic RLMErrorFileAccess, if no file was found when a realm was opened as read-only or if the directory part of the specified path was not found when a copy should be written.

Bug Fixes

Includes changes shipped in 0.97.1.

  • Fix incorrect results or crashes when using -[RLMResults setValue:forKey:] on an RLMResults which was filtered on the key being set.
  • Fix crashes when an RLMRealm is deallocated from the wrong thread.
  • Fix incorrect results from aggregate methods on Results/RLMResults after objects which were previously in the results are deleted.
  • Fix a crash when adding a new property to an existing class with over a million objects in the Realm.
  • Fix errors when opening encrypted Realm files created with writeCopyToPath.
  • Fix crashes or incorrect results for queries that use relationship equality in cases where the RLMResults is kept alive and instances of the target class of the relationship are deleted.

Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, or Twitter.

Read more

Installing Realm for Android: Why is it Changing?

by /

Limitations of Realm

In the year since we launched Realm for Android, we have been honored by the popularity of our library despite its limitations. In particular, we have heard many complaints about the requirement to extend classes from RealmObject, which in turns causes the following constraints:

  • No public fields
  • Only standard accessor names
  • No added logic to accessors
  • No custom methods
  • No implementing of interfaces

All these limitations come from a common reason: Realm is using proxy classes to perform zero-copy operations on the underlying data store. Let us go through all the limitations one by one.

No public fields

Java does not allow proxies to access fields, so Realm proxy classes cannot intercept when such fields are accessed. Also, fields are by definition stored in the Java heap. This means that data would have to be copied from Realm to Java memory, which is against our zero-copy practice.

Only standard accessor names

Annotations processors are extremely powerful tools, but they have some limitations. One of those is the inability to inspect the actual code of the class being proxied: only fields and methods names are available. This means that we had to rely on convention to make Realm proxy classes behave as expected.

No added logic to accessors

This is a direct consequence of the previous limitation. Since the implementation of the accessors cannot be accessed by the annotation processor, it is impossible to replicate such logic in the proxy classes. Of course we could simply call super.getMyField();, but that operates on the in-memory data, which is not being used in the proxy class.

No custom methods

Again, since the annotation processor cannot inspect code, it’s impossible to guess what a custom method actually does. Hence, Realm cannot allow such methods in order to guarantee correctness.

No implementing of interfaces

Since custom methods are not allowed, interfaces that require the implementation of methods are not allowed either.

So, How to Fix This?

The only way to overcome such limitations is with bytecode weaving. This means that after compilation is over, some modifications are applied to the .class files. We will go through the details of such operation in a future blog post. What’s important here is that the only way to cleanly perform bytecode weaving on Gradle builds is with a plugin. This is also what the popular libraries RetroLambda and Hugo are doing, so we know we are in good company!

Your build.gradle file

Until now, you installed Realm like this:

repositories {
    jcenter()
}

dependencies {
    compile 'io.realm:realm-android:<version>'
}

With the Gradle plugin, it looks like this:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:<version>"
    }
}

apply plugin: 'realm-android'

The first code sample should already be in your build.gradle file, so all you need to add are the lines staring with classpath and apply plugin: 'realm-android'.

Why Now?

Why do we provide the plugin now, even before the bytecode weaving step is released? There are actually some other reasons!

Smaller APKs!

Using the plugin we can now ship Realm as an AAR, as opposed to a JAR. We can also avoid including the annotation processor in the library and make it a standalone package. This means your final APKs will not have to include the annotation processor, shaving a few kilobytes off your app.

Easy ABI splits!

Another consequence of shipping an AAR is that now you are able to cleanly perform ABI splits without having to use the workaround described in our previous blog post. This means that you won’t have to ship a single APK containing native libraries for all CPU architectures.

What About Eclipse?

As you probably already know, Google is deprecating the ADT plugin for Eclipse and is ending its support at the end of the year. As far as we can tell, the vast majority of Android developers have already switched over to Android Studio, so that’s where we are focusing our efforts. That being said, our priorities are dictated by your feedback, and we will consider writing an Ant or Maven plugin if enough people ask for it.

Happy Coding!

We hope you will find this change useful! Please don’t hesitate to contact us. As always, we’re around on Stack Overflow, GitHub, and Twitter.

Read more

Year in Review: 2015

by /

2015 was a pretty busy year for Realm. From talks to releases, here are some of our favorite moments!

Releases

We had 24 releases this year, which took us from Realm Java 0.76 and Realm Cocoa 0.89 (remember when we only had Objective-C?) to Realm Java 0.87 and Realm Objective‑C & Swift 0.97.

Realm Java picked up better sorting, encryption, ARM64 & x8664 support, RealmModules, configurations, in-memory Realms, null support, an async API, a new migration API, a dynamic API _(Ed. note: How many APIs do you people need?), and most recently RxJava support.

Realm Cocoa of course had its biggest change in its Swift-first API, with all the associated Swift-y improvements. Other than that, all it got was encryption, sharing Realms between processes, Objective‑C generic support, support for watchOS & tvOS (Ed. note: How many OSs do you people need?), configurations, KVC collection operators, KVO, class subsets, and bitcode… so basically nothing else.

We also spent some time on a few side projects:

  • SwiftLint - Our Swift linter, which just launched this year!
  • jazzy - The Swift documentation generator, which went from lowly v0.0.19 to v0.4.1, adding support for Objective-C along the way, and is being used all over the web.
  • Realm Browser - Our OS X browser for Realm files, which is now on the App Store.

Blog posts

We published almost 200 articles to our blog this year. PHEW! We’re so happy that so many of you found them interesting! In case you missed some, here are a few of our favorites that are worth catching up on:

2016

With the way 2015 went down we feel like we’ve got a lot to live up to in 2016. We’re setting our sights even higher (25 releases!), and we’ve got big plans in the works. I hear you saying “Where’s my bulleted list of those?”. All in good time, friends, all in good time. For now, relax, enjoy your holidays, and Happy New Year, from all of us at Realm!

Read more

Realm Objective-C & Swift 0.97

by /

This is the last version of Realm Swift to support Swift 1.2.

We just released version 0.97 of Realm Objective-C and Realm Swift.

This release contains official support for tvOS, better Carthage support, more Objective-C API generics, performance & query improvements, deprecation removals and more!

tvOS 📺

You can now build Realm apps for the Apple TV! Although some enterprising users have been building & shipping apps for months already using our unofficial Apple TV development branch, it’s now a platform we officially support! 🎉

Because writing to the Documents directory is prohibited on tvOS, the default Realm path is set to NSCachesDirectory. However, please be mindful that tvOS can purge files in the Caches directory at any point, so we encourage you to rely on Realm as a rebuildable cache rather than storing important user data.

Building Realm Swift From Source Using Carthage

We’ve drastically simplified our build system to use a single Xcode project for both Realm Objective-C and Realm Swift, which means that Realm Swift can now be built using carthage --no-use-binaries.

Debugging Encrypted Realms

Until now, the mechanism used by our native encryption functionality relied heavily on Mach exception handling, which interfered with the operation of LLDB.

We’ve reworked the implementation of encryption so that it no longer relies on Mach exceptions, which means that it’s now possible to use LLDB to debug a process using an encrypted Realm. This also means that encryption no longer interferes with the behavior of crash reporters, which typically also rely on Mach exception handling. Finally, avoiding Mach exceptions means that platforms like tvOS & watchOS (which mark Mach APIs as unavailable) can now support encryption! Although we have yet to enable this for watchOS & tvOS pending further testing.

Generic Type Annotations in Realm Objective-C

Why let Swift have all the fun? Our Objective-C APIs have been updated to use generic type annotations wherever possible.

Breaking Changes

  • All functionality deprecated in previous releases has been removed entirely.
  • Adding a Realm notification block on a thread not currently running from within a run loop throws an exception rather than silently never calling the notification block.

Minor Enhancements

  • The block parameter of -[RLMRealm transactionWithBlock:]/Realm.write(_:) is now marked as __attribute__((noescape))/@noescape.
  • Many forms of queries with key paths on both sides of the comparison operator are now supported.
  • Add support for KVC collection operators in RLMResults and RLMArray.
  • Fail instead of deadlocking in +[RLMRealm sharedSchema], if a Swift property is initialized to a computed value, which attempts to open a Realm on its own.

Bug Fixes

  • Fix poor performance when calling -[RLMRealm deleteObjects:] on an RLMResults which filtered the objects when there are other classes linking to the type of the deleted objects.
  • An exception is now thrown when defining Object properties of an unsupported type.

Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, or Twitter.

Read more

Realm Java 0.87 — with RxJava support!

by /

We just released a new version of Realm Java to this website and to Maven. This release includes first-class API support for RxJava.

RxJava

RxJava is a Reactive Extensions library from Netflix that extends the Observer pattern. It makes it possible to work with changes to Realm data using composable sequences of operators. All Realm classes except RealmQuery and RealmList can now be exposed as an Observable(https://github.com/ReactiveX/RxJava/wiki/Observable).

Realm Observables are built on top of our standard RealmChangeListener, so any Observable will emit objects at the same rate as the change listener would have been notified.

Realm realm = Realm.getDefaultInstance();
RealmResults<Person> persons = realm.where(Person.class).findAll();
Person person = persons.first();

Observable<Realm> realmObservable = realm.asObservable();
Observable<RealmResults<Person>> resultsObservable = persons.asObservable();
Observable<Person> objectObservable = person.asObservable();

This also works with Realm’s Async API.

realm.where(Person.class).equalTo("name", "John").findAllAsync().asObservable()
  .filter(new Func1<RealmResults<Person>, Boolean>() {
      @Override
      public Boolean call(RealmResults<Person> persons) {
          // Ignore unloaded results
          return persons.isLoaded();
      }
  })
  .subscribe(new Action1<RealmResults<Person>>() {
      @Override
      public void call(RealmResults<Person> persons) {
          // Show persons...
      }
  });

See the RxJava example project for more examples.

Configuration

Although RxJava is now a first-class citizen in our API, it is still an opt-in dependency. This means you have to provide RxJava yourself in build.gradle. This has the benefits of letting you decide which version of RxJava you want to use and preventing method count bloat for projects that don’t use RxJava.

dependencies {
  compile 'io.realm:realm-android:0.87.0'
  compile 'io.reactivex:rxjava:1.1.0'
}

We also added a new interface called RxObservableFactory for people that want to customize how the Observables are created. A custom factory can be configured using RealmConfiguration, but Realm comes with a RealmObservableFactory class which is used as the default factory. It supports RxJava <= 1.1.*.

RealmConfiguration config = new RealmConfiguration.Builder(context)
  .rxFactory(new MyFactory())
  .build()

Work-in-progress

While we are shipping initial support for RxJava now, we still lack Observable support for RealmQuery and RealmList. These will be added in a future update.

It is also important to remember that RealmObject and RealmResults are still thread confined. This means that is not possible to load Realm objects on one thread and use them on another.

// Default pattern for loading data on a background thread
Observable.defer(new Func0<Observable<RealmResults<Person>>>() {
    @Override
    public Observable<RealmResults<Person>> call() {
        return realm.where(Person.class).findAll().asObservable();
    }
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<RealmResults<Person>>() {
    @Override
    public void call(RealmResults<Person> persons) {
        // Accessing persons here would crash.
    }
});

// Instead, use Realms Async API for the same effect
realm.where(Person.class).findAllAsync().asObservable()
  .subscribe(new Action1<RealmResults<Person>>() {
      @Override
      public void call(RealmResults<Person> persons) {
          // Show data in the UI
      }
  });

RealmObjects and RealmResults are also live objects, which means that they are continuously updated with the latest data from Realm. This is great for consistency, but doesn’t work well with RxJava’s model that favor immutable thread‑safe objects. Therefore, we have added Realm.copyFromRealm() which makes it possible to copy Realm data into normal Java objects, effectively detaching them from Realm. This has a cost in terms of both speed and memory usage but can make it easier to work with operators such as buffer().

// Get different versions of a person
realm.where(Person.class).findFirst().<Person>asObservable()
        .map(new Func1<Person, Person>() {
            @Override
            public Person call(Person person) {
                // Convert live object to a static copy
                return realm.copyFromRealm(person);
            }
        })
        .buffer(2)
        .subscribe(new Action1<List<Person>>() {
            @Override
            public void call(List<Person> persons) {
                // Without `map` and `copyFromRealm`, v1 and v2 would be the same
                Person v1 = persons.get(0);
                Person v2 = persons.get(1);
            }
        });

Solutions for avoiding this work-around will be added in a future update.

See the full changelog for all the details.


Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, and Twitter.

Read more

How 60Hz Went 100% Crash‑Free With Realm

by /

Today’s blogpost is by Suneth Mendis, cofounder at M2D2, who wrote to us about the M2D2 app 60Hz. Thanks Suneth!


60Hz is a simple app that helps users to keep track of their favourite TV shows. The app is in its 4th incarnation since its launch back in 2011.

The app churns through lot of data while operating. It has a large number of asynchronous background data-fetching tasks to keep the content in sync with the server. In v3.0, we introduced an NSCoding and keyed archiving technique to persist data in the app. This technique gave us the flexibility and stability we were after, but it carried a major flaw: accessing the persisted archive caused the device to heat up and eventually drain the battery, especially with large user libraries.

As a result, we re-wrote the entire application using Core Data in v4.0. First couple of releases of the app worked relatively well, with fewer crashes. However, the more changes we made to the Core Data schema, the more crashes seemed to come through. We worked really hard to isolate and fix these mysterious crashes, but by v4.1 things turned nasty. Our crash-free user rate was down to 60%, and our Twitter and Facebook feeds were filled with angry comments from our loyal users.

As a desperate measure, we turned to Realm. We had experimented with Realm for another project previously, but abandoned due to the lack of null properties. We realized Realm had matured since our last look and took the plunge to migrate from Core Data to Realm. The migration took few weeks to implement, but the results were stunning. Using Realm significantly reduced the complexity of the app, not to mention the neat and easy-to-understand data accessors. The current implementation of the app uses a combination of in-memory and persisted Realms to achieve the functionality. The crashes are no longer mysterious, thanks to very meaningful error messaging in Realm.

Since the launch of v4.2 few weeks ago, the crash-free user rate has gone up to 98% mark (sitting at 100% on most days). More than 120 DAUs compare to less than 80 previously.

Thank you Realm! I am sleeping well knowing our app is stable.


We’re glad we could help, Suneth! If you have a Realm success story, let us know!

Read more

Realm Java 0.86 — with new Migration API!

by /

We just released a new version of Realm Java to this website and to Maven. This release includes a replacement for the old Migration API, as well as a new Dynamic API to complement it.

Migration API

Migrations are still specified using a migration block in RealmConfiguration, but the interface has changed. Migrations now operate on a new Realm type called a DynamicRealm. DynamicRealm is a special variant of a conventional Realm that allows you to interact and change the schema while still having access to all of the ordinary object creation and query capabilities.

RealmMigration migration = new RealmMigration() {
  @Override
  public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {

     // DynamicRealm exposes an editable schema
     RealmSchema schema = realm.getSchema(); 

     if (oldVersion == 0) {
        // Migrate to version 1
        oldVersion++;
     }

     if (oldVersion == 1) {
        // Migrate to version 2
        oldVersion++;
     }
  }
}

// Configure the migration as normal
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context)
  .schemaVersion(2)
  .migration(migration)
  .build();

Classes and fields are now referenced using their names and can be created and modified in a fluent manner.

RealmSchema schema = realm.getSchema();

// Create Person class with two fields: name and age
schema.create("Person")
    .addField("name", String.class)
    .addField("age", int.class);

// Fields with special properties
schema.get("Person")
    .addField("id", long.class, FieldAttribute.PRIMARY_KEY);

// References to other Realm objects
schema.get("Person")
    .addRealmObjectField("favoriteDog", schema.get("Dog"))
    .addRealmListField("dogs", schema.get("Dog"));

// Creating new data during migrations
DynamicRealmObject person = realm.createObject("Person");
person.setString("name", "John");

// Delete a class and all its data
schema.remove("Person");

It is also possible to run custom transformations on all RealmObjects of a specific type. This can be useful if converting between types, or merging or splitting fields.

schema.get("Person")
  .transform(new RealmObjectSchema.Function() {
    @Override
    public void apply(DynamicRealmObject obj) {
      obj.setInt("age", obj.getInt("age") + 1); // Add 1 to all ages
    }
  });

See RealmSchema and RealmObjectSchema for all options, and take a look at our updated migration example.

Dynamic API

Migrations make use of the new Dynamic API, but it is also available outside migrations. It can be useful in scenarios where you are working with data where the model is not known at compile time, like importing data from CSV files.

Dynamic Realms are opened using the same configuration you use for the conventional Realms, but they ignore any schema, migration, and schema version.

RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
DynamicRealm realm = DynamicRealm.getInstance(realmConfig);

// In a DynamicRealm all objects are DynamicRealmObjects
DynamicRealmObject person = realm.createObject("Person");

// All fields are accessed using strings
String name = person.getString("name");
int age = person.getInt("age");

// An underlying schema still exists, so accessing a field that does not exist will throw an exception
person.getString("I don't exist");

// Queries still work normally
RealmResults<DynamicRealmObject> persons = realm.where("Person").equalTo("name", "John").findAll();

A DynamicRealm trades type safety and performance for flexibility, so only use it in cases where you really need the flexibility.

#enumsmatter

We have updated our query API so it now uses enums instead of booleans when specifying Sort and Case options. This should provide a more readable and type-safe API.

realm.where(Person.class)
  .beginsWith("name", "John", Case.INSENSITIVE)
  .findAllSorted("name", Sort.ASCENDING)

See the full changelog for all the details.


Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, and Twitter.

Read more

Realm named a startup to “bet your career on”

by /

We’re stoked to be included on Business Insider’s list of 50 enterprise startups to bet your career on in 2016.

Business Insider selects Realm as a startup to "bet your career on in 2016."

We hope you’ll take a bet on us and join the team! See our jobs page for our current available positions.

Thanks, Julie, for including us!

Read more

A Year of Using Realm in iComics

by /

Hi everyone!

As of today, I’ve now officially been using Realm in my current little side project app, shipping on the App Store for a whole year. To mark this milestone, I thought I’d write a quick piece on what that was like, including why I decided to go with Realm, what it was like converting an existing app to it, and what the resulting feedback from users was like.

The Epic Backstory

Since 2012, I’ve been building a DRM-free comic reader for iOS named iComics. The function of the app is very simple: take a ZIP file full of JPEG images, crunch some numbers, and present the images on-screen in the format of a comic book. The goal of the app is to enable users to read comics from online sources that don’t have their own dedicated app (such as Humble Bundle Books).

With elements like caching pre-processed file information, and saving/restoring the user’s reading progress, a proper data framework was required from the start. Initially, I toyed with the idea of using raw SQLite, but eventually chose instead to use this opportunity to try out Core Data for the first time. A lot of my friends had recommended Core Data to me over SQLite, so I was eager to see what it was like.

I won’t go into the specifics too deeply, but suffice it to say, working with Core Data was…a ‘challenge.’ The learning curve was huge, accessing data between threads was often unreliable, and if an error did occur, due to its very Apple-esque ‘black box model’, it sometimes took hours of trial and error to work out what was actually going wrong.

The straw that broke the camel’s back was in October 2014, when I had put the finishing touches on the update that would introduce iOS 7’s new design language. When I uploaded the build to TestFlight, literally every user reported that the app crashed on launch and woudn’t run. After doing some digging, I discovered that installing the update over the previous version was triggering a Core Data migration, which would reliably fail, and corrupt the database! What an absolute showstopper! I hadn’t noticed this at all during development since I was working off a fresh install, so no migrations were occurring.

So, it was at that point where I said a bunch of naughty words and decided to choose a new data storage framework. I was considering biting the bullet and moving to SQLite, when one of my colleagues pointed me at this ‘Realm’ thing and suggested I give it a try. I remember thinking to myself, ‘What the hell. It’s worth a shot. There’s absolutely no way it could make things worse than Core Data did.’

Literally three hours later, there was no longer any trace of Core Data in my codebase; just Realm.

And it just worked.

Straight away. I remember sitting on my couch in utter shock and disbelief for a few minutes simply repeating, “That was it? Really? No way. I’m missing something. It can’t have been that easy. Impossible. Something’s going to explode in my face down the line.”

But no! One TestFlight build release later, and it was clear from the unanimous response from the testers that Realm had instantly made all of Core Data’s problems go away. It felt like magic.

Converting From Core Data to Realm

To be completely honest, I’d actually heard of Realm a few months before adopting it (possibly right after it was announced!). My colleague had showed me the news article talking about it, and I went as far as to download the sample apps and had a play with it. My impression was, ‘Yeah, that’s definitely cool. But surely it would be a lot of effort to switch over from Core Data.’

With many, MANY custom UIView subclasses, and a large number of third-party libraries, the iComics codebase is around 160,000 lines of code (I’m sure that’s not something to be proud of!). As such, I was very wary that doing anything so fundamental as completely replacing the data layer would take a VERY long time to implement and, given the architecture of the code, maybe even impossible. It was only after Core Data catastrophically failed, to the point where the app was rendered un-shippable, that I was motivated to give Realm a try.

Like I said earlier, converting an app of a relatively non-trivial size from Core Data to Realm took mere hours. While Realm doesn’t technically follow the proper conventions of object-relational mapping (ORM) technologies, its API design is sufficiently similar in that it’s very easy to map out its logic in a way that matches (but doesn’t emulate) Core Data. It was simply a matter of converting my NSManagedObject subclasses to RLMObject subclasses, converting any NSNumber properties to straight-up NSInteger values, and then changing any portions of the code related to querying/saving to the database to the equivalent Realm statements.

What amazed me the most about Realm, as compared to Core Data, was the sheer lack of code and auxiliary files that were required to achieve the same thing. No .xcdatamodeld files; the schema is derived from the model classes themselves with no boilerplate initialization code; simply two or three lines of code to configure the default Realm file’s settings.

As a sidenote, deleting all of that boilerplate Core Data code felt good. Really really good.

One Year Later

A whole year later, and Realm really has exceeded my expectations. The number of thread-related data crashes/corruptions has dropped to zero (as far as my analytics have told me!), and many users have written that the app somehow ‘feels’ snappier than the previous Core Data version.

Additionally, as Realm has matured and more features have been added in these past months, I’ve been able to refine its integration in the app. Since originally adding Realm to iComics, additional features have been added:

  • Being able to configure the default Realm file (such as its location on disk)
  • Accessing Realm files from different processes
  • Key-value observing on model properties
  • Most recently, null property support

Each and every one of these features have meant I could go back and remove much of the original custom code I’d written to ‘simulate’ these features in my app and now rely directly on that functionality in Realm. This has directly lowered my own technical debt as well as made the app more architecturally sound in the process.

Suffice it to say, there has never been a moment in the past 365 days when I regretted ditching Core Data for Realm.

Where to From Here?

While Realm is working incredibly well for me, I’m acutely aware that my app was originally architected for Core Data, and that Realm was (somewhat awkwardly) ‘shoe‑horned’ into Core Data’s place.

Core Data and Realm work in fundamentally different ways. Core Data tries to be clever about batch-loading and then keeping objects in memory, whereas Realm eschews that in favour of lazy-loading data on cue, but in an ultimately faster way.

As a result of that, a lot of my app has been designed to potentially try and cope with concepts like paging groups of objects, and offloading tonnes of work to background threads when it really isn’t necessary to do so with Realm. As a result, I’m planning to rip out the data-heavy components of my app and rewrite them from scratch; this time with a Realm-centric mindset as the goal. Hopefully this would result in less code required to maintain, and even faster, more efficient operation of the app.

Conclusion

So…yeah. Realm is good. Very good. I’m sold.

When I was looking to jump ship from Core Data, my other options were either raw SQLite or JSON. In hindsight, going with either of those would have been an absolute disaster. SQLite would have required a hilarious amount of additional bridging code (e.g., converting SQL queries into objects) and JSON would have been incredibly inefficient.

Suffice it to say, I definitely feel like I made the right choice with Realm, and I’m looking forward to many more years of integrating it into my apps.

Read more

Realm Java 0.85 — with new encryption implementation!

by /

We just released a new version of Realm Java to this website and to Maven. This release replaced the signal handler–based encryption implementation with a more generic solution which works on all devices. Also a new API, Realm.isEmpty(), was added.

New Encryption Implementation

As we mentioned in our previous post, “A Look Into Realm’s Core DB Engine”, we used to rely on the POSIX signal handler to implement Realm’s encryption. It’s a really simple and elegant solution, from a software point of view. But when it comes into the real Android world, the signal handler becomes the root cause of a few weird crashes.

  • Starting with 5.0 Lollipop, Android began shipping a Chromium WebView that can be installed and updated through the Play Store. Unfortunately there was a bug in the WebView v40 that could cause encrypted Realms to crash if used together. More information can be found here.
  • A few older devices (HTC One X for example) do not work correctly with the signal handler. The same problem on the HTC One X happened to Firefox for Android as well. See this Bugzilla page for more details.

Although we tried to use workarounds to enable the encryption on as many devices as we could, using the signal handler on a device like the HTC One X is an impossible mission, because the relevant API on the device is broken. That’s why we decided to rewrite our whole encryption implementation. From this version (v0.85.0) on, Realm’s encryption will work on all Android devices!

So now you can remove the catch block of RealmEncryptionNotSupportedException and let Realm encrypt the data on any Android devices.

New API - Realm.isEmpty()

Now you can check if a Realm contains any data by calling Realm.isEmpty().

Breaking Changes

RealmEncryptionNotSupportedException is removed since it is not needed anymore. 🎉

Realm.executeTransaction() now directly throws any RuntimeException instead of wrapping it in a RealmException. If there is something wrong in the transaction block while calling Realm.executeTransaction(), the original exception will be thrown to make it easier to debug. When exceptions occur, the transaction will be rolled back, just like before.

RealmQuery.isNull() and RealmQuery.isNotNull() now throw IllegalArgumentException instead of RealmError if the field name is a linked field and the last element is a link.

Read more

Realm Java 0.84 — with Async Queries & Transactions!

by /

We just released a new version of Realm Java to this website and to Maven. This release includes support for asynchronous queries and asynchronous write transactions!

Android applications are inherently asynchronous, and thus one of the most requested features was the ability to execute Realm read queries or write operations asynchronously on a worker thread.

Asynchronous Queries

You can now execute queries asynchronously on a worker thread.

Async queries are very similar to our existing, synchronous queries. You can keep using the same fluent API to build the query, but the last method in the call will decide the behavior if the RealmQuery is synchronized (findAll()) or asynchronous (findAllAsync()).

Example: finding users with name “John” or “Peter”

First create the query:

RealmResults<User> result = realm.where(User.class)
                              .equalTo("name", "John")
                              .or()
                              .equalTo("name", "Peter")
                              .findAllAsync();

Note that the query is not blocking and immediately returns a RealmResults<User>. This is a promise (similar to the concept of Future in standard Java). The query will continue to run in a background thread, and once it completes it will update the returned instance of RealmResults with the appropriate results.

If you want to be notified of the query completion, you can register a callback. This callback will also be called every time the query is refreshed to reflect the latest changes in Realm (usually after a commit).

private RealmChangeListener callback = new RealmChangeListener() {
    @Override
    public void onChange() { // called once the query complete and on every update
    // use the result
    }
};

public void onStart() {
    RealmResults<User> result = realm.where(User.class).findAllAsync();
    result.addChangeListener(callback);
}

Since we hold a strong reference to the listener, don’t forget to remove any registered listener to avoid leaking the enclosing class.

public void onStop () {
    result.removeChangeListener(callback); // remove a particular listener
    // or 
    result.removeChangeListeners(); // remove all registered listeners
}

At any time you can check if the returned RealmResults has completed or not

result.isLoaded()

Calling isLoaded on a RealmResults obtained synchronously will always return true.

Non-Looper threads caveat: The Async query needs to use the Realm’s Handler in order to deliver results consistently. Trying to call an asynchronous query using a Realm opened inside a thread without a Looper will throw an IllegalStateException

Asynchronous Transactions

You can now also execute write transactions asynchronously on a worker thread.

It works the same way as the current executeTransaction, but instead of opening a Realm on the same thread, it will give you a background Realm opened on a different thread to work with.

You can register a callback if you wish to be notified when the transaction completes or fails (this also requires the Realm’s Handler to deliver the callback. If you start an async write from a Realm opened from a non-Looper thread, you won’t get the notification):

realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm bgRealm) {
                User user = bgRealm.createObject(User.class);
                user.setName("John");
                user.setEmail("[email protected]");
            }
        }, new Realm.Transaction.Callback() {
            @Override
            public void onSuccess() {
            }

            @Override
            public void onError(Exception e) { 
                // transaction is automatically rolled-back, do any cleanup here 
            }
        });

The callback is optional and can be null if you want to fire and forget:

realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm bgRealm) {
                User user = bgRealm.createObject(User.class);
                user.setName("John");
                user.setEmail("[email protected]");
            }
        }, null);

We hold a strong reference to the callback until the write transaction completes. In case you want to cancel a pending transaction (e.g. you’re quitting your Activity/Fragment) don’t forget to call cancel — it will attempt to cancel the scheduled transaction and remove the reference to your callback in order to avoid leaking the instance/enclosing class:

RealmAsyncTask transaction = realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm bgRealm) {
            }
        }, null);

// configuration change ... 

public void onStop () {
    if (transaction != null && !transaction.isCancelled()) {
        transaction.cancel();
    }
}

New query options

We’ve added two new ways of doing queries: isEmpty() and distinct().

RealmQuery.isEmpty() can be used to test if a value is not null but considered empty, i.e. a RealmList or byte array with 0 elements is empty and the String "" is empty. isEmpty() does not work on number values.

// Find all users with no dogs
RealmResults<User> users = realm.where(User.class).isEmpty("dogs").findAll(); 

// Find all users with at least 1 dog
RealmResults<User> users = realm.where(User.class).not().isEmpty("dogs").findAll(); 

Realm.distinct() can be used to return a distinct set of elements as defined by a given field. distinct will only work on fields that are indexed (@Index or @PrimaryKey).

// Returns the set of users that all have a different name
RealmResults<User> users = realm.distinct(User.class, "name");

More utility methods

We’ve added some extra utility methods that make it possible to ask about the state of the Realm before interacting with it:

  • Realm.isClosed(): Checks if the underlying Realm file is still open.
  • Realm.isInTransaction(): Checks if the Realm is currently in a write transaction.
  • RealmQuery.isValid(), RealmList.isValid(), RealmResults.isValid(): Checks if the underlying Realm hasn’t been closed or the data deleted.

See the full changelog for all the details.


Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, and Twitter.

Read more

Realm Objective-C & Swift 0.96

by /

Realm files read or written by this version cannot be opened with previous versions of Realm. Please be careful about shipping updates to your existing apps!

We just released version 0.96 of Realm Objective-C and Realm Swift.

This release contains official support for null properties, keypath collection queries (count/min/max/sum/avg), a new RealmCollectionType protocol in Swift, error handling in writes, and a fistful of bug fixes!

Last week, we published a beta version of this release but now we feel this is ready for prime time.

Null Support

This version adds support for null values for all property types.

Objective-C

NSString *, NSDate *, NSData * now allow nil by default. You can disallow setting a property to nil by overriding the +requiredProperties class method and including the names of the properties which you want to disallow nil for. Accessing a Realm file created with a previous version will automatically convert these properties to nullable in the file itself, unless explicitly marked not to do so in +requiredProperties.

Optional numbers can be stored using an NSNumber * property which is tagged with the type of the number. You can use NSNumber<RLMInt> *, NSNumber<RLMBool> *, NSNumber<RLMFloat> *, and NSNumber<RLMDouble> *.

@interface OptionalTypes : RLMObject
@property NSString *optionalString;
@property NSString *requiredString;
@property NSData *optionalData;
@property NSDate *optionalDate;
@property NSNumber<RLMInt> *optionalInt;
@property NSNumber<RLMBool> *optionalBool;
@property NSNumber<RLMFloat> *optionalFloat;
@property NSNumber<RLMDouble> *optionalDouble;
@end
@implementation OptionalTypes
+ (NSArray *)requiredProperties {
    return @[@"requiredString"];
}
@end

Swift

String, NSDate and NSData properties work as you’d expect them to and can either be optional or non-optional. Unfortunately, we’re unable to directly support optional numeric types (see #2147), so you have to wrap the types in RealmOptional. For example:

class OptionalTypes: Object {
    dynamic var string: String? = "B"
    dynamic var data: NSData? = "C".dataUsingEncoding(NSUTF8StringEncoding)
    dynamic var date: NSDate? = NSDate(timeIntervalSince1970: 10)
    let int = RealmOptional<Int>(1)
    let float = RealmOptional<Float>(2.2)
    let double = RealmOptional<Double>(3.3)
    let bool = RealmOptional<Bool>(true)
    let boolWithNilDefault = RealmOptional<Bool>(nil)
}

As with List properties, RealmOptional properties should always be declared with let and not be declared dynamic. The actual value of the RealmOptional is read from and written to the value property.

Automatic Conversion

Realm files opened with this version will be automatically converted to the new file format on first access, even when only accessed in a read transaction. This automatic conversion will perform the following operations:

  1. All indexes will be recreated (only applies to ints and strings).
  2. All NSString, NSDate, and NSData properties are converted to nullable, unless marked as required in +requiredProperties.
  3. The new format version number will be written to the file.

Since this writes to the file, Realm files created with a previous version of Realm won’t be able to be read with this new version. If you’re bundling a Realm file in your app, it will have to be updated to use this new file format.

Note that this format conversion is irreversible.

Manual Migration

Please note that even though the file format upgrade happens seamlessly in the background, a schema migration in order to adopt nullable properties still needs to be performed. Even if you haven’t made any changes to your object schema in the interim, certain properties are now made nullable by default, and so you may be required to make changes to your code if you want to keep the schema the same as before. That’s especially the case when you have NSString, NSDate and NSData properties used from Objective-C, which are - as explained as above - optional by default. So assuming you had a model like shown below originally:

@interface Dog : RLMObject
@property NSString *name;
@property NSDate *birthdate;
@property Person *owner;
@end

@implementation Dog
@end

As a dog owner, you usually know your dog’s name - clearly a required property - but if you may have adopted it, you might not know the exact birthdate - something that can be considered optional. In this case, you would need to define the name as a required property in an overridden implementation of +requiredProperties on the class Dog as shown here.

@implementation Dog
+ (NSArray *)requiredProperties {
    return @[@"name"];
}
@end

Since at this point birthdate is now implicitly optional, you will still need to define a basic migration in order to properly update the schema to accomodate this. In the past, you may have provided arbitrary data to serve as default values, such as [NSDate dateWithTimeIntervalSince1970:0], which is admittedly very ambiguous in relation to birthdates, but as this is no longer necessary, you may want to go back any of your existing objects to make sure you remove any arbitrary values and properly replace them with null ones.

// Inside your [AppDelegate didFinishLaunchingWithOptions:]
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];

// Set the new schema version. This must be greater than the previously used
// version. If you've never set a schema version before, the version is 0,
// so assuming that'd be your first migration, we set it to 1.
config.schemaVersion = 1;

// Set the block which will be called automatically when opening a Realm with a
// schema version lower than the one set above
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
    // We haven’t migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
        [migration enumerateObjects:Person.className
                          block:^(RLMObject *oldObject, RLMObject *newObject) {
            // convert null-placeholders to actual nils
            newObject[@"birthdate"] = [oldObject[@"birthdate"] timeIntervalSince1970] > 0 ? oldObject[@"birthdate"] : nil;
        }];
        
        // Note: Even if you don't have to convert placeholder values,
        // you still have to provide at least an empty migration block
        // when your schema has changes to nullability of properties.
    }
};

The first access of [RLMRealm defaultRealm] will cause the file format to be upgraded automatically, and will execute the migration.

Keypath Collection Queries

Keypath collection queries using @count, @min, @max, @sum and @avg are now supported on RLMArray/List properties. See our handy NSPredicate Cheatsheet for more details on how to use these.

RealmCollectionType

RealmCollectionType is deprecated and has been replaced by RealmCollection. The section below is retained in its original state for posterity, but you should see here for the latest on `RealmCollection`.

Users of Realm Objective-C have had the ability to represent both RLMArray and RLMResults using their shared protocol (RLMCollection) for a long time. We’re now reflecting that protocol in Swift, while expanding what it can do.

Functionality common to both List and Results is now declared in a RealmCollectionType protocol that both types conform to. A type-erased wrapper is also provided, so Swift can store a reference to the underlying collection despite its layout being different:

class ViewController: UIViewController {
    var collection: AnyRealmCollection

    init(collection: RealmCollectionType) {
        super.init()
        self.collection = AnyRealmCollection(collection)
    }
}

Improved Error Handling

In current versions of Realm committing a write transaction on a severely space-constrained device would cause Realm to crash. Thankfully, Realm’s crash safety would prevent existing data from being corrupted, but this wasn’t exactly a solid user experience.

Now committing write transactions via commitWrite / commitWriteTransaction and write / transactionWithBlock optionally allow for handling errors when the disk is out of space.

Minor Enhancements

  • Added isEmpty property on RLMRealm/Realm to indicate if it contains any objects.

Bug Fixes

  • Fix assertion failure when inserting NSData between 8MB and 16MB in size.
  • Fix assertion failure when rolling back a migration which removed an object link or RLMArray/List property.
  • Add the path of the file being opened to file open errors.
  • Fix crashes when the first Realm opened uses a class subset and later Realms opened do not.
  • Fix inconsistent errors when Object(value: ...) is used to initialize the default value of a property of an Object subclass.
  • Throw an exception when a class subset has objects with array or object properties of a type that are not part of the class subset.
  • Fix a crash that could be triggered by rapidly opening and closing a Realm many times on multiple threads at once.
  • Fix several places where exception messages included the name of the wrong function which failed.

Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on StackOverflow, GitHub, or Twitter.

Read more