Realm Blog

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

Realm Java 0.83 — with Null Support!

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 a Realm Java update to this website, and to Maven. This release includes support for null values, one of the most-frequently requested Realm features!

Breaking Changes

With this release, fields of the types String, Date, and byte[] are now nullable by default. (In previous versions of Realm Java, no fields could have the value null.) Existing apps will have to either modify model classes or provide a migration step to explicitly support this new feature. Read on for details.

In order to be able to support null values, Realm’s underlying storage engine has changed its file format. Your Realm files will automatically be converted to new file format when you open the Realm file for the first time. The file format conversion is irreversible! It is not possible to open the new Realm file using a previous version of Realm. Furthermore, it is not possible to downgrade a Realm file to the old file format.

If you are going to upgrade existing apps, we recommend that you test carefully before shipping.

Boxed types

Realm Java supports the most common types in Java, including boolean, integer types (byte, short, int, and long), and floating-point numbers (float and double). These primitive (or unboxed) types cannot be assigned to null in Java, and thereby they have served us well. You can still use the primitive types in your model classes. As before, the primitive types indicate that the field cannot be assigned to null.

On the other hand, boxed types are common in Java, and variables and fields of boxed types can be assigned to null. We are introducing boxed types for booleans (Boolean), integers (Byte, Short, Integer, and Long), and floating-point numbers (Float and Double) to Realm Java. When you use these boxed types in your model classes, the field can be assigned to null.

Fields of the types String, Date, and byte[] can be null. Setting a RealmList field to null means that the list is cleared. No objects are removed, only the references to the objects are removed. Moreover, a RealmList field cannot be null. The getter will always return a RealmList object but the length of the list might be zero.

Let us show you a little example. The model class below has two integer fields and one string field.

class Person extends RealmObject {
    String name;
    int age;
    Integer weight; // weight is not required!
}

You can create objects, and assign values to the fields.

Person john = realm.createObject(Person.class);
john.setName("John");
john.setAge(25);
john.setWeight(73);

Person bill = realm.createObject(Person.class);
bill.setName("Bill");
bill.setAge(41);
bill.setWeight(null);

As you can see, we set all three fields for John, while we don’t know the weight of Bill and set it to null (actually, the default value for Person.weight is null so we can skip the line).

The new @Required annotation

Strings, Dates, byte[], and box typed fields can all be assigned to null. As the example above showed, sometimes a proper value (not null) is required. You can specify that a field cannot be null by using the new @Required annotation. Using this annotation, Realm will not allow you to set it to null. If you will always know the name of a person, a better model class is:

class Person extends RealmObject {
    @Required
    String name;
    int age;
    Integer weight;
}

It is possible to add the @Required annotation to boxed typed fields, and Realm will enforce that no null values are saved. The annotation is not used for the primitive types, as a field of a primitive type cannot be null. Moreover, relationships (RealmList and single Realm objects) cannot be required.

Querying

For any field which is not required, you can query with null as a value. Moreover, aggregate functions (sum, min, etc.) will not take null values into account. The Realm interpretation of null implies that every string begins with, ends with, and contains null. This means that the following query will return all objects:

RealmResults<Person> persons = realm.where(Person.class).where().beginsWith("name", null).findAll();

If you query with null as a value for required fields, an exception is thrown.

Migration

With the release supporting null, Realm’s underlying storage engine will automatically convert your Realm files. The conversion is required as the file format used by the storage engine has been changed. The conversion is done even though you don’t intend to use null values in your model classes. The automatic conversion will take time, so the very first access to a Realm file will take a bit longer. After the conversion, files will be opened just as fast as before.

You are likely to do some manual migration as well. If you have string, date or binary (byte[]) fields in your model classes, you will have to migrate them. In previous versions of Realm Java, Strings could not be null. In version 0.83.0 of Realm Java, the semantics of String has been changed. Take the following model class as an example:

class Dog {
    String name;
    int age;
}

If you have created a Realm file which includes Dog, the field name could not be assigned to null. With Realm Java 0.83.0 and later, if you which to disallow null as a value, you must change the model class to:

class Dog {
    @Required
    String name;
    int age;
}

If you don’t wish to change the model class (or wish to use null), you will have to migrate the Realm file. For that purpose, you can use the method Table.convertColumnToNullable() as part of your migration.

RealmMigration migration = new RealmMigration() {
    @Override
    public long execute(Realm realm, long version) {
        Table table = realm.getTable(Dog.class);
        table.convertColumnToNullable(table.getColumnIndex("name"));
        return 1;
    }
};

RealmConfiguration realmConfig = new RealmConfiguration.Builder(getContext())
    .schemaVersion(1)
    .schema(Dog.class)
    .migration(migration)
    .build();
Read more

Leonardo Kim joins Realm

by /

We’re happy to announce that Leonardo has joined Realm and will be helping us from Seoul, Korea.

김용욱 님이 대한민국 서울에서 렘과 함께 일하게 되었다는 사실을 알릴 수 있어 기쁩니다.

Leonardo Kim 김용욱

Leonardo YongUk Kim is a software developer with extensive experience in mobile and embedded projects, including: several WIPI modules (Korean mobile platform based on Nucleus RTOS), iOS projects, a scene graph engine for Android, an Android tablet, a client utility for black boxes, and some mini games using Cocos2d-x. He has also developed many open source projects.

Additionally, Leonardo has been an organizer of GDG Korea Android for the last several years. To date, he has organized conferences, codelabs, hackathons, and meetups.

Get in touch with Leonardo on Facebook, GitHub or email. Welcome to Realm, Leonardo!

김용욱님이 대한민국 서울에서 Realm에 합류 하였습니다.

김용욱님은 많은 모바일 프로젝트와 임베디드 프로젝트를 개발한 소프트웨어 프로그래머로 WIPI, iOS, 씬 그래프 엔진, 안드로이드 타블렛, 블랙박스, Cocos2d-x로 작성된 미니게임 등의 다양한 프로젝트에 참여했습니다.

그는 또한 GDG 코리아 안드로이드의 오거나이저로 몇년간 활동해왔습니다. 그는 몇몇 오픈소스 프로젝트를 개발하고 컨퍼런스, 코드랩, 해커톤, 밋업을 개최하였습니다.

김용욱님을 페이스북, 깃헙, 이메일를 통해 만나보세요. 용욱님 환영합니다!

Realm Community in Korea

Realm is a mobile database: a replacement for SQLite & Core Data. It’s easy to use, fast, and cross platform.

The Realm community in Korea has expanded rapidly since our public launch in July 2014. From the start, we’ve prioritized the Korean developer community; Tim Anglade, our VP of Product unveiled Realm for Android publicly while on stage at Seoul’s DEVIEW conference in September, 2014. This year, we expanded and presented at both GDG Android and DEVIEW 2015.

In Korea, we organize regular meetups in Seoul to share knowledge, host technical presentations, and help Realm users meet one another. In the future, we plan to organize a coding club, hackathons, and more. Many Korean apps are already using Realm, including: Retrica, Cymera, RidiBooks, CJmall, and Interpark. We hope your app will join this list!

Please join us on the Realm Korea Page where we share the latest news about Realm & mobile development. We also have a Realm Korea User Group on Facebook to help you solve technical problems, share case studies, presentations, tips, and more. Feel free to ask your questions in Korean there or email [email protected]. Happy hacking!

Realm 은 Android와 iOS 에서 SQLite와 Core Data를 대체해 사용하실 수 있는 모바일 데이터베이스입니다. 오픈소스로 무료로 사용하실 수 있고, 간결하고 짧은 코드로 편하게 개발할 수 있으며 속도가 빨라 더 나은 사용성의 앱을 만들 수 있습니다. 현재 Starbucks, Amazon, Ebay 등에서 모바일 앱 개발에 사용되고 있습니다.

Realm 사용자 커뮤니티는 2014년 7월에 Realm SDK 가 공개된 이후 빠르게 발전해 왔습니다. Realm은 2014 DEVIEW 컨퍼런스에서 Realm: Android와 iOS를 위한 데이터베이스 세션을 진행 하였고, Realm Android SDK는 그 세션에서 공개 되었습니다. 이는 Realm 이 한국 Android 사용자를 얼마나 중요하게 생각하고 있는지를 보여줍니다. 현재 카카오헬로, 네이버 폴라, 싸이메라, 리디북스, CJmall 를 포함한 다양한 한국 앱들이 이미 Realm을 사용하고 있습니다.

2014년에 제품을 발표한 이래 한국에서 꾸준히 Realm 개발자 모임을 진행하고 있습니다. 최근에는 8월에 네이버 D2에서 Realm 개발자 모임을 가졌습니다.

앞으로도 한국에서 정기적인 개발자모임을 가지고 기술정보를 교환하는 등 모바일 개발자들들 위한 자리를 만들 계획입니다. 또한 코딩 클럽, 해커톤, 코드랩 등의 행사도 기획하고 있습니다. 페북에서 운영중인 Realm 한국 사용자 그룹 에 기술이슈나 사용 경험, 프리젠테이션 자료, 사용 팁 등을 공유해 주시고 Realm 한국 사용자 페이지와도 방문해 주십시오. 한국어 연락처는 [email protected] 입니다. 감사합니다.

Read more

Makoto Yamazaki joins Realm

by /

We’re happy to announce that Realm’s recent agreement with uPhyca Inc. has resulted in Makoto Yamazaki, a.k.a. @zaki50, joining our team! Makoto will support Realm’s development in Japan, focusing mainly on the Android platform.


株式会社ウフィカとRealmが契約を結び、山﨑 誠(@zaki50)がRealmの活動に加わることになりました! 主にAndroidを中心に、Realm自体の開発と日本における利用を支援してまいります。

Makoto Yamazaki

As a seasoned Java and Android expert, Makoto has already developed many apps. He has also given technical presentations at several Android conferences, including Android Bazaar and Conference (ABC) and DroidKaigi.

In addition to helping us develop Realm software, Makoto will also support Japanese developers by sharing information and maintaining a helpful presence in the community.

Japanese developers have already been talking about Realm on channels such as Twitter, Facebook, Stack Overflow, and Slack, thanks to Katsumi Kishikawa, another Realm team member based in Japan. With Makoto’s help, we are confident that we will provide even better support to Japanese developers.

You can follow Makoto on Twitter and GitHub, or you can even drop him an old fashioned email.

山﨑はJavaおよびAndroidのエキスパートとして様々なアプリケーションの開発に携わってきただけでなく、Android Bazaar and Conference(ABC)DroidKaigi など各種Android関連イベントでの豊富なプレゼンテーション経験をもっています。

これらの経験をもとに、これからはRealmの開発だけでなく、日本の開発者のみなさんとRealmをつなぐ存在として積極的に情報発信と支援活動をおこなってまいります。

現在Realmでは、TwitterFacebook GroupStack Overflow日本語版Slackを日本の開発者のみなさんとのコミュニケーションのチャンネルとして活用しています。 これまでは岸川がひとりで日本の開発者のみなさんを支援してまいりましたが、山﨑が加わることでより一層充実した支援体制となることを確信しております。

TwitterGitHubで山﨑をフォローしてください。また、困ったことや要望があれば、どんなことでもお気軽にメールしてください。

Realm Community in Japan

Realm is a mobile database: a replacement for SQLite & Core Data. It’s easy to use, fast, and cross platform.

The Realm community in Japan is very active. We regularly organize meetups to share knowledge, host technical presentations, and help Realm users meet one other. Many Japanese apps are already using Realm, including AWA, Nikkei, Eight, Sync by Wantedly, and ChatWork.

Please join our Realm Japan User Group on Facebook to find help solving technical problems, as well as case studies, presentations, and tips for using Realm. We also run Realm Slack. Feel free to join us there and ask any questions you have, in Japanese or English. Happy Hacking!

RealmはSQLiteやCoreDataの代替となるべくオープンソースソフトウェアとして開発されているモバイルデータベースです。クロスプラットフォーム(現在はiOSとAndroid)で利用でき、シンプルなAPIで簡単に利用することができ、動作速度が非常に高速であることが特長です。この利点を活かして、より短期間で使い勝手の良いアプリケーションを開発することが可能になります。

すでに日本では音楽ストリーミングサービスのAWA日本経済新聞 電子版、名刺管理のEightSync by WantedlyChatWorkなど数多くのアプリケーションでRealmが使用されています。

デベロッパーコミュニティに対する活動として、毎月のRealmミートアップの開催や、各種の勉強会、ミートアップをサポートしています。

また、私たちはFacebookにユーザーグループRealm Japan User Groupを開設して、技術情報の共有、新機能のお知らせ、アプリケーションの紹介など、日本のデベロッパーの皆さんの情報交換をサポートしています。

より複雑な質問にはSlackチャットによるサポートを活用しており、迅速な問題解決に役立っています。もちろん、質問は日本語でしていただいて構いません。

We’re Hiring!

Welcome to Realm, Makoto!

If you’d like to work with Makoto and the rest of us at Realm, take a look at our jobs page, or drop Tim a line.

Read more

Realm Objective-C & Swift 0.96 Beta

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 made a special release of Realm Objective-C & Swift numbered “0.96.0-beta”. This release can be installed manually using our zip release for Objective-C or Swift, or by specifying this exact version in your Podfile or Cartfile. For the RealmSwift pod, you’ll need to use 0.96.0-beta2.

This release contains early 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!

We encourage you to try out this version in your local development environments. Although we’ve taken every precaution to test this new file format and the migration process, we’re relying on your feedback to catch any possible issues before we cut an official release.

After a period of beta-testing, these features will be made available as part of an official 0.96.0 release.

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.

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

Editor’s Note: 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.

Again, we encourage you to try out this version in your local development environments. Although we’ve taken every precaution to test this new file format and the migration process, we’re relying on your feedback to catch any possible issues before we cut an official release.

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 Objective-C & Swift 0.95.1

by /

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

New Technologies

Now that Xcode 7 is officially out, all the new technologies that it brings are now officially supported: Swift 2.0, iOS 9, watchOS 2 & OS X 10.11.

We’ve been testing and building for these new technologies for months now, so you should feel confident that Realm will run smoother than ever with this release.

We’ll still be supporting Swift 1.2 via the swift-1.2 branch for some time to come, but we encourage you to move to Swift 2 as soon as possible.

Bug Fixes

Along with support for new Apple technologies, we’ve included a number of bug fixes in this release:

  • We added missing KVO handling for moving and exchanging objects in RLMArray and List.
  • We fixed a crash due to race condition in RLMRealmConfiguration where the default configuration was in the process of being copied in one thread, while released in another.
  • We fixed a crash when a migration which removed an object or array property is rolled back due to an error.
  • Setting the primary key property on persisted RLMObjects / Objects via subscripting or key-value coding will cause an exception to be thrown.

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

Groupon

by /

Groupon App Screenshots

At the time of this writing, many apps on the iOS App Store are powered by Realm. A lot of them are brand new and still relatively small, while some have already reached critical success, and others even exceeded that, earning Apple’s coveted ‘Essentials’ badge.

This week, we’re proud to recognize a very prominent app, straight from Apple’s “Essentials” collection: Groupon!

If you haven’t heard of it before, Groupon is a global service aimed at connecting users and merchants in the same area, letting users take advantage of special discounts and deals of merchants around them. Merchants can advertise their products or services as separate discounted ‘coupons’ via the Groupon app that users can simply buy directly in the app. These coupons are then saved in the user’s account, and may be redeemed for their full value from the merchant at a later date.

The model is both amazingly simple and effective. The discounted prices aren’t trivial, with certain products and services being advertised for 50% off or more. Even without buying anything from the app, it’s a great advertising channel for merchants to let users find out about them!

Of course, if you hadn’t already guessed, we’re absolutely thrilled that the Groupon apps are powered by Realm. Groupon has been an early adopter of Realm, and we couldn’t be happier that it fit their scale requirements well.

Also, while we have the chance, special recognition should also be given to Groupon for letting the Swift Language Users Group meetup periodically host events at their incredibly beautiful office in Palo Alto.

From everyone at Realm, we thank Groupon for leveraging our tech in their fantastic, worldwide service (as well as allowing the use of their offices)! We wish them the very best in their endeavors, and will continue to support them in the future!

Read more