Realm Blog

Realm Objective-C & Swift 2.0 – Mobile Platform Support

by /

We’re releasing version 2.0 of Realm Objective‑C and Realm Swift today, adding support for the Realm Mobile Platform. Also included in this release is one source breaking change for Swift 3 and bug fixes. Read on to learn more!

Realm Mobile Platform Extensions

If you haven’t read the Realm Mobile Platform launch post yet, please do that now so we can get back to the technical cocoa bits! (err, nibs? 😄)

Let’s start with a quick look at what it takes to configure a synchronized Realm:

// Authenticating the User
User.authenticate(with: .google("google token"),
                  server: URL(string: "https://realm.example.com:9443")) { user, error in
  if let user = user {
    // Opening a remote Realm
    let realmURL = URL(string: "realm://realm.example.com:9080/~/userRealm")!
    let config = Realm.Configuration(syncConfiguration: (user, realmURL))
    let realm = try! Realm(configuration: config)
    // Any changes made to this Realm will be synced across all devices!
  } else if let error = error {
    // handle error
  }
}

That’s it! Once a Realm is opened like this, any changes made to it will be automatically synchronized across all other devices for that user.

Back to technical bits. To support the Mobile Platform, we’ve added some new classes and APIs:

Sync User & Credential

Sync Users are a central concept when dealing with synchronized Realms. Every Realm is associated with a user. The user can be authenticated to a Realm via a username/password credential or through a number of additional authentication methods (Google, Facebook, iCloud, etc.). See docs on users for details.

Sync Configuration

To configure a synchronized Realm, you must set the syncConfiguration property of RLMRealmConfiguration/Realm.Configuration with the user and the remote realm URL (e.g. realm://realm.example.com:9080/~/userRealm). See our docs for more details.

Sync Manager & Session

The sync manager (RLMSyncManager/SyncManager) is a singleton (for the time being) that manages all synchronized Realms. You’ll mostly interact with it to set the sync engine’s log level, or to specify a global error handler.

Each synchronized Realm has a corresponding session (RMLSyncSession/SyncSession) which can provide further information about its state. We intend to attach more information to this in upcoming releases.

Platform Extensions are in Beta

Although the underlying technology for Realm synchronization has been built, refined and stabilized over the last 5 years, we want to make sure we get the APIs right before committing to them. So we’re releasing the platform extensions as a beta. These APIs will change in future releases. We’re doing this to make sure we end up with the best possible product.

If your app doesn’t use the platform extensions, you can continue to count on the reliability of Realm just like you always have. The platform extensions have been designed in a way that clearly differentiates from using Realm entirely locally or using a synchronized Realm, so this should be easy to identify if your app relies on any of the beta components.

A (mostly) non-breaking 2.0 release

This is a major version bump for our frameworks to reflect the magnitude of the new features and capabilities included in this release. However, we’ve chosen to not introduce API breaking changes, because we realize this release comes just a few months after our 1.0 release and we value the time it takes for you, our users, to update your apps for API changes. With one exception… In Realm 1.1.0 we introduced official Swift 3 APIs and the most common feedback we got there was how it wasn’t ideal that RealmSwift.Error conflicted with the standard library Swift.Error. So by popular demand, we’ve nested our Error into a Realm extension, and this is the only source-breaking change in this release.

Note that Realm Objective-C and Swift 2.0 introduces a new file format that allows us to gain performance improvements and fix some bugs. Files written by Realm 2.0 cannot be read by 1.x or earlier versions. Old files can still be opened.

Removing some extra files

The .log, .log_a and .log_b files no longer exist and the state tracked in them has been moved to the main Realm file. This reduces the number of open files needed by Realm, improves performance of both opening and writing to Realms, and eliminates a small window where committing write transactions would prevent other processes from opening the file.

Bug Fixes

  • Fix an assertion failure when sorting by zero properties.
  • Fix a mid-commit crash in one process also crashing all other processes with the same Realm open.
  • Properly initialize new nullable float and double properties added to existing objects to null rather than 0.
  • Fix a stack overflow when objects with indexed string properties had very long common prefixes.
  • Fix a race condition which could lead to crashes when using async queries or collection notifications.
  • Fix a bug which could lead to incorrect state when an object which links to itself is deleted from the Realm.

Q: Can I use Realm with its newly open sourced core storage engine?

Yes! You can build and use Realm as an embedded database built 100% from open source components. Although the installation steps are a bit more involved than pod install, but you can follow the instructions listed in the READMEs for both realm-core and realm-cocoa.

We’re working on adding a way to install entirely from source using CocoaPods in the next few weeks. Stay tuned!

We’d like to remind you that we will continue to support Xcode 7.3.1 and Swift 2.2 as long as we can, but encourage all our users to migrate to Xcode 8 as soon as possible.


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 2.0 - Mobile Platform Support

by /

We’re releasing version 2.0 of Realm Java today, adding support for the Realm Mobile Platform as well as some other minor changes and bug fixes.

Realm Mobile Platform Extensions

If you didn’t read the Realm Mobile Platform launch post yet, we suggest you do that now in order to make more sense of the technical details that will soon follow.

First you need to enable the Mobile Platform Extensions by adding the following to your app’s build.gradle file:

realm {
  syncEnabled = true
}  

Then, let’s take a quick look at what it takes to configure a synchronized Realm:

// Login a user
Credentials credentials = Credentials.usernamePassword(username, password, true);
User.loginAsync(credentials, "https://realm.example.com:9443", new User.Callback() {
  @Override
  public void onSuccess(User user) {
    // Opening a synchronized Realm
    // All changes to this Realm will be synchronized with all devices
    SyncConfiguration config = new SyncConfiguration.Builder(user, "realm://realm.example.com/~/userRealm").build();
    Realm realm = Realm.getInstance(config);
  }
  
  @Override
  public void onError(ObjectServerError error) {
    // Handle error
  }
});

That’s it! Once a Realm is opened like this, any changes made to it will be automatically synchronized across all other devices for that user.

Back to the technical bits. To support the Realm Mobile Platform, we’ve added some new classes and APIs:

User & Credential

Users are a central concept when dealing with synchronized Realms. Every Realm is associated with a user. The user can be authenticated to a Realm via a username/password credential or through a number of additional authentication methods (Google, Facebook, iCloud, etc.). See docs on users for details.

Sync Configuration

To configure a synchronized Realm, you must create a SyncConfiguration tied to the user and the remote Realm URL (e.g., realm://realm.example.com/~/userRealm). See our docs for more details.

Sync Manager & Session

The SyncManager is a singleton that manages all synchronized Realms. Currently, you will most likely interact with it to specify a global error handler or how users are stored.

Each synchronized Realm has a corresponding Session which can provide additional information about its state. We intend to attach more information to the session in upcoming releases.

Platform Extensions are in Beta

Although the underlying technology for Realm synchronization has been built, refined and stabilized over the last 5 years, we want to make sure we get the APIs right before committing to them. So we’re releasing the platform extensions as a beta. These APIs will change in future releases. We’re doing this to make sure we end up with the best possible product. Feedback on the APIs is appreciated.

If your app doesn’t use the platform extensions, you can continue to count on the reliability of Realm just like you always have. The platform extensions have been designed in a way that clearly differentiates from using Realm entirely locally or using a synchronized Realm. This should make easy to identify if your app relies on any of the beta components.

All APIs that are in beta are marked with a @Beta annotation and tag in respectively code and Javadoc.

Other 2.0 changes

This is a major version bump for our frameworks to reflect the magnitude of the new features and capabilities included in this release. At the same time we have streamlined a few things as well as made a few adjustments to bring the Realm Java more in line with Realm Swift and Realm Objective-C.

Note that Realm Java introduces a new file format that allows us to gain performance improvements and fixes some bugs. Files written by Realm 2.0 cannot be read by 1.x or earlier versions. Old files can still be opened and they will be migrated to the new format automatically. NOTE: If you are shipping prebuild Realm files with your app, you have to upgrade those to the new version. You can use Realm Browser to upgrade to the latest file format.

Global initializer

The Context reference was sneaking into more and more of our APIs, causing unnecessary friction. In the end we took a step back and introduced a global initializer function

Realm.init(context);

This also made it possible to remove the context from other parts of the APIs which means that:

  • Creating a RealmConfiguration.Builder() no longer requires a context.
  • RealmConfiguration.Builder.assetFile() no longer requires a context.
  • Realm.getDefaultInstance() now works without setting a default first.
  • More failsafe loading of native code.

A natural place for calling this method is in an Application subclass:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Realm.init(this);
        // Other initializers
    }
}

Default Values

With Realm Java 2.0 we support default values when creating objects. This implies that it is possible to define default values for fields and in the default constructor.

public class Person extends RealmObject {
  private String name = "John";
  private int age;
  
  public Person() {
    this.age = 42;
  }
}

Person p = realm.createObject(Person.class);
p.getName(); // John
p.getAge(); // 42

Default values will also be applied when creating objects from JSON data, but not when creating objects using the dynamic API.

RealmLog

A new class has been added to the public API called RealmLog. It makes it possible to customize how much is logged from Realm and how. All events from the Realm Mobile Platform are also routed through this class.

RealmLog.clear(); // Remove all loggers
RealmLog.add(new AndroidLogger(Log.DEBUG)); // Add custom logger

Objects with Primary Keys

In order to support merging objects from other devices, two new restrictions are imposed on objects with primary keys:

1) A primary key must be provided when the object is created. 2) Once a primary key is set it cannot be changed.

First restriction should only be visible if you use realm.createObject(Class) to create objects. In that case it is required to set the value of the primary key by using realm.createObject(Class, Object).

Using realm.copyToRealm() and realm.createObjectFromJson() will continue to work as before.

If you, for some reason, need to change the primary key, it is necessary to create a new object and copy all fields over. copyFromRealm()/copyToRealm() can be used to make that process easier.

Bug fixes and other changes

For a full list of bug fixes and other changes, see the Changelog.


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 1.1.0 – Official Swift 3 APIs & Xcode 8 Support

by /

We will continue to support Xcode 7.3.1 and Swift 2.2 as long as we can, but encourage all our users to migrate to Xcode 8 as soon as possible.

We’re releasing version 1.1.0 of Realm Objective‑C and Realm Swift today, adding support for Xcode 8, Swift 2.3, Swift 3.0, with frameworks linked against iOS 10, macOS 10.12, tvOS 10 and watchOS 3. Also included in this release are some minor non-breaking API improvements, performance improvements and bug fixes. Read on to learn more!

Swift 3 API Refinements

Those of you keeping up with changes to Swift already know how big a jump Swift took from versions 2.x to 3.0!

We’ve audited Realm Swift’s public API in preparation for this and made some adjustments to reflect changes to Swift’s syntax and API design guidelines. We strived to strike a balance between conforming to the API guidelines without drastically changing ours APIs at their call site (i.e., in your code), so changes to your code should be minimal…

Here are some examples of how Realm Swift looks in Swift 2.2 and Swift 3.0:

// Swift 2.2/2.3
let config = Realm.Configuration(
  schemaVersion: 1,
  migrationBlock: { migration, oldSchemaVersion in
    migration.renamePropertyForClass(Person.className(), oldName: "yearsSinceBirth", newName: "age")
    migration.enumerate(Person.className()) { oldObject, newObject in
      // Migrate Person
    }
  }
)

let realm = try! Realm(configuration: config)
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan'").sorted("name")
let jim = Person()
try! realm.write {
  jim.dogs.appendContentsOf(sortedDogs)
}

// Swift 3.0
let config = Realm.Configuration(
  schemaVersion: 1,
  migrationBlock: { migration, oldSchemaVersion in
    migration.renameProperty(onType: Person.className(), from: "yearsSinceBirth", to: "age")
    migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
      // Migrate Person
    }
  }
)

let realm = try! Realm(configuration: config)
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan'").sorted(byProperty: "name")
let jim = Person()
try! realm.write {
  jim.dogs.append(objectsIn: sortedDogs)
}

For simplicity, our documentation throughout the site has been updated to use Swift 3 exclusively. That includes code samples, long form docs and API docs.

API breaking changes

  • Deprecate migrateRealm: in favor of a new performMigrationForConfiguration:error: method that follows Cocoa’s NSError conventions.
  • Fix an issue where RLMResults used id instead of its generic type as the return type of subscript.

Enhancements

  • Improve error message when using NSNumber incorrectly in Swift models.
  • Further reduce the download size of the prebuilt static libraries.
  • Improve sort performance, especially on non-nullable columns.
  • Allow partial initialization of an object by initWithValue:, deferring required property checks until the object is added to a Realm.

Bug Fixes

  • Fix incorrect truncation of the constant value for queries of the form column < value for float and double columns.
  • Fix a crash when an aggregate is accessed as an Int8, Int16, Int32, or Int64.
  • Fix a race condition that could lead to a crash if an RLMArray or List was deallocated on a different thread than it was created on.
  • Fix a crash when the last reference to an observed object is released from within the observation.
  • Fix a crash when initWithValue: is used to create a nested object for a class with an uninitialized schema.
  • Enforce uniqueness for RealmOptional primary keys when using the value setter.

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 1.1.0 — New and faster Insert API!

by /

We just released a new version of Realm Java to this website and to Bintray. It contains a new insert API as well as a number of bug fixes.

Insert API

Realm’s storage engine has always been faster than SQLite when it comes to inserting data, but due to a number of design decisions in the Realm Java API, that advantage was mostly lost. This meant that Realm was generally as fast as SQLite for a small number of items (<1000), but started getting slower the more items you added in a batch.

In v1.1.0 we came up with some optimizations and now offer 4 new methods:

  • void Realm.insert(RealmModel obj)
  • void Realm.insert(Collection collection)
  • void Realm.insertOrUpdate(RealmModel obj)
  • void Realm.insertOrUpdate(Collection collection)
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
realm.insertOrUpdate(restApi.getPersons());
realm.commitTransaction();

These methods differ mostly from the standard Realm.copyToRealm() in the sense that they do not return any objects. This has allowed us to reduce memory allocations to almost zero as well as remove many checks that were pure overhead.

Doing this, we went from being ~40% slower than an optimized SQLite implementation to being ~70% faster for 100K objects.

Realm Batch Insert Benchmark

We have released our benchmarks repo so you can verify these numbers yourself. Find it here. The numbers above were produced on a Nexus 6P using stock Android 6.0.1.

Note that due to Realm’s auto-update features it is possible to query for data before they are even saved, and you will get notified when the data is available. This can be a huge benefit for those of you that want to separate displaying data from saving it:

final PersonApi api = new PersonApi();
Realm realm = Realm.getDefaultInstance();
RealmResults<Person> persons = realm.where(Person.class).findAllAsync();
person.addChangeListner(new RealmChangeListener() {
    @Override
    public void onChange(RealmResults<Person> persons) {
      if (!persons.isEmpty()) {
	    // Callback when data is available
      }
  }
});

realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm realm) {
      realm.insertOrUpdate(api.getPersons());
    }
});

Bug fixes

  • Combining async transactions and async queries on the UI thread could result in the transaction onSuccess callback being invoked before the data is available on the UI thread.

  • The RealmOptionalAPITransformer introduced in 1.0.1 does not work with DexGuard and has been disabled for now.

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 Xamarin 0.76.0 released

by /

We’ve released version 0.76.0 of Realm Xamarin. This includes the first external contribution, by Joe Brock: support for INotifyPropertyChanged. This adds change notifications to your Realm objects when using data binding with Xamarin Forms. For more information, see From Data Bindings to MVVM in the Xamarin Docs. NuGet should already be telling you that the update is available in existing projects and new projects that you add it to will use the new version out of the box.

Major Changes

  • RealmObject classes will now implicitly implement INotifyPropertyChanged if you specify the interface on your class. Thanks to Joe Brock for this contribution!

Minor Changes

  • long is supported in queries
  • Linker error looking for System.String System.String::Format(System.IFormatProvider,System.String,System.Object) fixed
  • Second-level descendants of RealmObject and static properties in RealmObject classes now cause the weaver to properly report errors as we don’t (yet) support those.
  • Calling .Equals() on standalone objects no longer throws.

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 Xamarin 0.75.0 released

by /

We’ve released version 0.75.0 of Realm Xamarin. This is the first release after the launch, introducing some essential features and fixes. NuGet should already be telling you that the update is available in existing projects and new projects that you add it to will use the new version out of the box.

Breaking Changes

  • File format of Realm files is changed. Files will be automatically upgraded but opening a Realm file with older versions of Realm is not possible. NOTE: If you were using the Realm Browser specified for the old format you need to upgrade. Pick up the newest version here.
  • RealmResults<T> no longer implicitly implements INotifyCollectionChanged. Use the new ToNotifyCollectionChanged method instead.

Major Changes

  • RealmResults<T> can be observed for granular changes via the new SubscribeForNotifications method.
  • Realm gained the WriteAsync method which allows a write transaction to be executed on a background thread.
  • Realm models can now use byte[] properties to store binary data.
  • RealmResults<T> received a new ToNotifyCollectionChanged extension method which produces an ObservableCollection<T>-like wrapper suitable for MVVM data binding.

Minor Fixes

  • Nullable DateTimeOffset properties are supported now.
  • Setting null to a string property will now correctly return null
  • Failure to install Fody will now cause an exception like “Realms.RealmException: Fody not properly installed. RDB2_with_full_Realm.Dog is a RealmObject but has not been woven.” instead of a NullReferenceException
  • The PCL RealmConfiguration was missing some members.
  • The Fody weaver is now discoverable at non-default NuGet repository paths.

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

13,949 Commits and 6,148 Closed Issues Later: Thank You for Helping Realm Reach 1.0

by /

It was July of 2014 when we announced Realm as “the first mobile-first database.” Today — 13,949 commits and 6,148 closed issues later — we’re proud to release Realm 1.0, a major milestone not only for Realm as a company and a product, but also for the iOS and Android developer communities that have embraced Realm.

When we launched, we only offered an Objective-C version of Realm for iOS and Mac developers. First-class support for Swift and an Android version were added later, and just recently we launched initial support for React Native and Xamarin. As a result, Realm is now available to every major mobile platform and programming language. This release is the culmination of more than two years of hard work building and shipping products, and we could not have gotten here without the tremendous support of the community. Thank you! 👏

Even before reaching 1.0, Realm has been broadly adopted by the mobile dev community. You’ve given us over 12,000 stars on GitHub (and counting). Realm is currently used by more than 100,000 active developers and in tens of thousands of apps, including apps with massive usage from companies like Starbucks, Twitter, Anheuser-Busch, NBCUniversal, Alibaba, eBay, and thousands more. They are using Realm because Realm makes their apps better — the developers behind those apps can build better user experiences, more easily and more quickly. With today’s 1.0 release, they can be further assured that Realm products for iOS and Android have reached a key stage of maturity and stability.

To see what has changed, you can look at our changelogs for Java, Objective-C, and Swift.

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 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 even enhancing performance. With Realm, you can model complex data, link objects in a graph, and compose advanced queries.

// Define you model class by extending RealmObject
public class Dog extends RealmObject {
    private String name;
    private int age;

    // ... Generated getters and setters ...
}

public class Person extends RealmObject {
    @PrimaryKey
    private long id;
    private String name;
    private RealmList<Dog> dogs; // Declare one-to-many relationships

    public Person(long id, String name) {
        this.id = id;
        this.name = name;
    }

    // ... Generated getters and setters ...
}

// Use them like regular java objects
Dog dog = new Dog();
dog.setName("Rex");
dog.setAge(1);

// Create a RealmConfiguration that saves the Realm file in the app's "files" directory.
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);

// Get a Realm instance for this thread
Realm realm = Realm.getDefaultInstance();

// Query Realm for all dogs younger than 2 years old
final RealmResults<Dog> puppies = realm.where(Dog.class).lessThan("age", 2).findAll();
puppies.size(); // => 0 because no dogs have been added to the Realm yet

// Persist your data in a transaction
realm.beginTransaction();
final Dog managedDog = realm.copyToRealm(dog); // Persist unmanaged objects
Person person = realm.createObject(Person.class); // Create managed objects directly
person.getDogs().add(managedDog);
realm.commitTransaction();

// Listeners will be notified when data changes
puppies.addChangeListener(new RealmChangeListener<RealmResults<Dog>>() {
    @Override
    public void onChange(RealmResults<Dog> results) {
        // Query results are updated in real time
        puppies.size(); // => 1
    }
});

// Asynchronously update objects on a background thread
realm.executeTransactionAsync(new Realm.Transaction() {
    @Override
    public void execute(Realm bgRealm) {
        Dog dog = bgRealm.where(Dog.class).equals("age", 1).findFirst();
        dog.setAge(3);
    }
}, new Realm.Transaction.OnSuccess() {
    @Override
    public void onSuccess() {
      // Original queries and Realm objects are automatically updated.
      puppies.size(); // => 0 because there are no more puppies younger than 2 years old
      managedDog.getAge();   // => 3 the dogs age is updated
    }
});
// Define your models like regular Objective‑C classes
@interface Dog : RLMObject
@property NSString *name;
@property NSData   *picture;
@property NSInteger age;
@end
@implementation Dog
@end
RLM_ARRAY_TYPE(Dog)
@interface Person : RLMObject
@property NSString             *name;
@property RLMArray<Dog *><Dog> *dogs;
@end
@implementation Person
@end

// Use them like regular Objective‑C objects
Dog *mydog = [[Dog alloc] init];
mydog.name = @"Rex";
mydog.age = 1;
mydog.picture = nil; // properties are nullable
NSLog(@"Name of dog: %@", mydog.name);

// Query Realm for all dogs less than 2 years old
RLMResults<Dog *> *puppies = [Dog objectsWhere:@"age < 2"];
puppies.count; // => 0 because no dogs have been added to the Realm yet

// Persist your data easily
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
  [realm addObject:mydog];
}];

// Queries are updated in real-time
puppies.count; // => 1

// Query and update the result in another thread
dispatch_async(dispatch_queue_create("background", 0), ^{
  Dog *theDog = [[Dog objectsWhere:@"age == 1"] firstObject];
  RLMRealm *realm = [RLMRealm defaultRealm];
  [realm beginWriteTransaction];
  theDog.age = 3;
  [realm commitWriteTransaction];
});
// Define your models like regular Swift classes
class Dog: Object {
  dynamic var name = ""
  dynamic var age = 0
}
class Person: Object {
  dynamic var name = ""
  dynamic var picture: NSData? = nil // optionals supported
  let dogs = List<Dog>()
}

// Use them like regular Swift objects
let myDog = Dog()
myDog.name = "Rex"
myDog.age = 1
print("name of dog: \(myDog.name)")

// Get the default Realm
let realm = try! Realm()

// Query Realm for all dogs less than 2 years old
let puppies = realm.objects(Dog).filter("age < 2")
puppies.count // => 0 because no dogs have been added to the Realm yet

// Persist your data easily
try! realm.write {
  realm.add(myDog)
}

// Queries are updated in real-time
puppies.count // => 1

// Query and update from any thread
dispatch_async(dispatch_queue_create("background", nil)) {
  let realm = try! Realm()
  let theDog = realm.objects(Dog).filter("age == 1").first
  try! realm.write {
    theDog!.age = 3
  }
}
// Define your models and their properties
class Car {}
Car.schema = {
  name: 'Car',
  properties: {
    make:  'string',
    model: 'string',
    miles: 'int',
  }
};
class Person {}
Person.schema = {
  name: 'Person',
  properties: {
    name:    {type: 'string'},
    cars:    {type: 'list', objectType: 'Car'},
    picture: {type: 'data', optional: true}, // optional property
  }
};

// Get the default Realm with support for our objects
let realm = new Realm({schema: [Car, Person]});

// Create Realm objects and write to local storage
realm.write(() => {
  let myCar = realm.create('Car', {
    make: 'Honda',
    model: 'Civic',
    miles: 1000,
  });
  myCar.miles += 20; // Update a property value
});

// Query Realm for all cars with a high mileage
let cars = realm.objects('Car').filtered('miles > 1000');

// Will return a Results object with our 1 car
cars.length // => 1

// Add another car
realm.write(() => {
  let myCar = realm.create('Car', {
    make: 'Ford',
    model: 'Focus',
    miles: 2000,
  });

// Query results are updated in real-time
cars.length // => 2
// Define your models like regular C# classes
public class Dog : RealmObject 
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person Owner { get; set; }
}

public class Person : RealmObject 
{
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; } 
}

var realm = Realm.GetInstance();

// Use LINQ to query
var puppies = realm.All<Dog>().Where(d => d.Age < 2);

puppies.Count(); // => 0 because no dogs have been added yet

// Update and persist objects with a thread-safe transaction
realm.Write(() => 
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Rex";
    mydog.Age = 1;
});

// Queries are updated in real-time
puppies.Count(); // => 1

// LINQ query syntax works as well
var oldDogs = from d in realm.All<Dog>() where d.Age > 8 select d;

// Query and update from any thread
new Thread(() =>
{
    var realm2 = Realm.GetInstance();

    var theDog = realm2.All<Dog>().Where(d => d.Age == 1).First();
    realm2.Write(() => theDog.Age = 3);
}).Start();

Why use Realm?

Easy

Realm’s primary focus has always been ease of use. Developers tell us they switch even large apps to Realm in hours, and save weeks of implementation, optimization & debugging time on an average project.

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 raw SQLite, despite offering a rich object-based API. Although we always recommend that everyone test their own use-cases, developers usually see huge speedups when porting apps to Realm.

Cross-platform

Realm supports Java, Objective-C, React Native, Swift and Xamarin. You can share Realm files across platforms, use the same data models, and write similar business logic on all platforms. For debugging, .realm files can be opened with 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, use an advanced query language, rely on built-in AES256 encryption, and even easily integrate Realm data into your UI through optional add-ons.

Trusted

Have a large app or a large userbase? Realm’s the database for you. We’re already trusted in production by banks and healthcare providers, and proven across complex enterprise apps and #1 hits on both the Apple App Store and Google Play Store.

Community-driven

Realm is built in the open on GitHub. Features are prioritized based on user requests and we welcome contributions. We have over 12,000 stars on GitHub, and beyond the core projects, our community has already been building hundreds of apps, plugins & components.

Supported

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

Who is using Realm?

Realm is built into apps used by over a billion people.

Twitter

Even #1 app store successes trust Realm. Twitter’s innovative video app Vine and its 200M monthly active users started using Realm in 2016.

Starbucks

The Fortune 500 retailer relies on Realm in their flagship app, allowing you to order ahead from your phone and reap rewards at the counter.

Alibaba

The NYSE-listed Chinese juggernaut uses Realm in its flagship marketplace business, allowing both suppliers & buyers to sell & buy goods on a platform that generated almost $3 billion USD in revenues last year.

Budweiser

The Global 500 giant built their innovative TapWiser app on Realm. It allows bars & stores to quickly order new kegs & bottles directly from a mobile app, since most outlets don’t have a computer on site.

SAP

If you’re a Concur user, chances are you’ve used Realm already: expense reports & travel plans are managed in this app that serves over 20,000 clients and 30 million end-users.

Rite Aid

The Fortune 500 retail giant trusts Realm to securely store data for customers, via the EnvisionRx program.

Other notable users include: Amazon, eBay, Google, GoPro, Walmart, Adidas, Cisco, NBCUniversal, Nike, the NFL and many, many more.

What’s Next

We’d love your feedback on what we can improve, and are here to help you along the way on Stack Overflow and Twitter!

Get Started with Realm Java - or check out the source on GitHub
Get Started with Realm Objective-C - or check out the source on GitHub
Get Started with Realm Swift - or check out the source on GitHub
Get Started with Realm React Native - or check out the source on GitHub
Get Started with Realm Xamarin - or check out the source on GitHub

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

Read more

Realm Objective‑C & Swift 0.103 – Dropping Support For Older Versions, Plus Improvements

by /

We’re releasing version 0.103 of Realm Objective‑C and Realm Swift today, with a few minor breaking changes and improvements. Read on for more information.

Breaking Changes

  • All functionality deprecated in previous releases has been removed entirely.
  • Support for Xcode prior to 7.3 & Swift prior to 2.2 has been completely removed.
  • RLMResults/Results now become empty when a RLMArray/List or object they depend on is deleted, rather than throwing an exception when accessed.
  • Migrations are no longer run when deleteRealmIfMigrationNeeded is set, recreating the file instead.

Enhancements

  • Added invalidated properties to RLMResults/Results, RLMLinkingObjects/LinkingObjects, RealmCollectionType and AnyRealmCollection. These properties report whether the Realm the object is associated with has been invalidated.
  • Some NSErrors created by Realm now have more descriptive user info payloads.

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

Introducing Realm Xamarin

by /

Today we’re launching a new Realm mobile database, this time built specifically for Xamarin. It offers easy object persistence and full query capabilities, with a performance profile that’s 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.

public class Dog : RealmObject
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person Owner { get; set; }
}

var realm = Realm.GetInstance();

// Query with LINQ
var puppies = realm.All<Dog>().Where(d => d.Age < 2);
puppies.Count(); // => 0 because no dogs have been added yet

// Writes in a transaction
realm.Write(() =>
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Rex";
    mydog.Age = 1;
});

// Queries are updated in real-time
puppies.Count(); // => 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 for React Native earlier in 2016. We are already used on hundreds of millions of devices today by appmakers including Twitter, Starbucks, Cisco, Walmart, Google, Amazon, & eBay, plus many many others.

Today, we’re launching for Xamarin, Microsoft’s mobile framework that lets developers write C# code that becomes native iOS & Android apps.

Realm Xamarin brings the modern design & simplicity you expect from Realm, and will allow you to target both iOS and Android with the same codebase. We currently support Xamarin.iOS and Xamarin.Android, and look forward to supporting Xamarin.Mac in the future, as well as UWP and Unity.

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 C# 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 even enhancing performance. With Realm, you can model complex data, link objects in a graph, and compose advanced queries.

public class Dog : RealmObject
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person Owner { get; set; }
}

var realm = Realm.GetInstance();

realm.Write(() =>
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Rex";
    mydog.Age = 9;
});
// Basic query with LINQ fluent or extension syntax
var oldDogs = realm.All<Dog>().Where(d => d.Age > 8);
// or
var oldDogs = from d in realm.All<Dog>() where d.Age > 8 select d;

// Queries can be chained
var dogsNamedRex = oldDogs.Where(p => p.Name == "Rex");
dogsNamedRex.Count(); // => 1

// Writes happens in a thread-safe transaction
realm.Write(() =>
{
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Rex Maximus";
    mydog.Age = 10;
});

// Query results are updated in real-time
dogsNamedRex.Count(); // => 2
public class Person : RealmObject
{
    public string Name { get; set; }
    public RealmList<Dog> Dogs { get; }
}

var realm = Realm.GetInstance();

realm.Write(() =>
{
    var jim = realm.CreateObject<Person>();
    var mydog = realm.CreateObject<Dog>();
    mydog.Name = "Fido";
    mydog.Owner = jim;
});

You can see more examples of how to use these APIs in our sample apps.

Why use Realm?

Easy

Realm’s primary focus has always been ease of use, and as you can see from the samples above, Realm Xamarin has the same overall goal. 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 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

This should go without saying, but Realm Xamarin obviously allows you to write your app once in C# and target both iOS & Android. Please note 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 LINQ, and even easily integrate Realm data in Xamarin.Forms.

Trusted

Realm Xamarin is built on top of the same core as Realm Java, Objective‑C, React Native, and 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.

Community-driven

Realm Xamarin is built in the open on GitHub. Features are prioritized based on user 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 May 9, 2016, using the latest versions available of Realm, sqlite-net and Couchbase Lite. Measurements taken on an iPhone 6S Plus with 128GB memory running iOS 9.3.1. Source. We recommend you perform your own benchmarks that represents your use cases as any synthetic benchmarks can only provide rough indicators.

What’s Next

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 .NET and want UWP support or Unity support, please speak up — we’d love to add that in the future.

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

Read more

Realm Objective‑C & Swift 0.102 – Rename Properties in Migrations or Skip Them Altogether!

by /

Support for Xcode 6.x and Swift older than 2.2 is deprecated and will be removed entirely in our next release.

We’re releasing version 0.102 of Realm Objective‑C and Realm Swift today, adding two small migration-related features: the ability to rename properties in migrations, or to configure your Realm file to be deleted whenever a migration would have previously been required. Read on for more information.

Renaming Properties in Migrations

It’s now possible to rename properties as part of migrations. Renaming a property is more efficient than copying values and preserves relationships rather than duplicating them.

To rename a property during a migration, make sure that your new models have a property by the new name and don’t have a property by the old name.

If the new property has different nullability or indexing settings, those will be applied during the rename operation.

Here’s how you could rename Person’s yearsSinceBirth property to age:

// Inside your application(application:didFinishLaunchingWithOptions:)

Realm.Configuration.defaultConfiguration = Realm.Configuration(
  schemaVersion: 1,
  migrationBlock: { migration, oldSchemaVersion in
    // We haven’t migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
      // The renaming operation should be done outside of calls to `enumerate(_:)`.
      migration.renamePropertyForClass(Person.className(), oldName: "yearsSinceBirth", newName: "age")
    }
  })
// Inside your [AppDelegate didFinishLaunchingWithOptions:]

RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = 1;
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
  // We haven’t migrated anything yet, so oldSchemaVersion == 0
  if (oldSchemaVersion < 1) {
    // The renaming operation should be done outside of calls to `enumerateObjects:`.
    [migration renamePropertyForClass:Person.className oldName:@"yearsSinceBirth" newName:@"age"];
  }
};
[RLMRealmConfiguration setDefaultConfiguration:config];

Deleting Realms When a Migration is Required

It’s quite common to modify a Realm schema numerous times during development, but writing fully-fledged migrations at that stage is time consuming and distracting when you’re just trying to “get the job done”…

So in this version, we’re adding a deleteRealmIfMigrationNeeded boolean property to RLMRealmConfiguration/Realm.Configuration. This flag defaults to false so you won’t start suddenly losing data if you upgrade to this version of Realm, unless you explicitly opt in to this feature.

Bug Fixes

  • Fix crash when migrating to the new date format introduced in 0.101.0.
  • When using BETWEEN on an RLMArray/List property, only match when a single related object is within the request range, rather than allowing different objects in the list to satisfy the upper and lower bounds.
  • Fix crash when querying inverse relationships when objects are deleted.
  • Fix a race condition when a Realm is opened on one thread while it is in the middle of being closed on another thread.

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.101 – Better Dates, Memory Overhead & Crash Handling!

by /

Realm files read or written by this version cannot be opened with previous versions of Realm. Existing files will automatically be upgraded when they are opened. Please be careful about shipping updates to your existing apps!

We’re releasing version 0.101 of Realm Objective‑C and Realm Swift today, addressing some long-standing limitations regarding date precision, memory mapping overhead, multi-process crash handling, and more.

Nanosecond Precision Dates & New File Format

Until now, NSDate properties have discarded their sub-second values, leading to some surprising behavior in apps requiring sub-second precision in dates. This release includes a new date format that’s even more precise than NSDate, so date properties maintain their full precision.

This new property type format required an update to the overall Realm file format, meaning that Realm files read or written by this version cannot be opened with previous versions of Realm. Existing files will automatically be upgraded when they are opened, except for read-only files bundled with your app, which you can upgrade by opening them in the Realm Browser. Please be careful about shipping updates to your existing apps! 🚨

Reduced Multi-Threaded Memory Mapping Overhead

Previous versions of Realm needed to mmap the entire file for each thread in order to preserve transaction isolation. This isolation is why Realm doesn’t have a concept of “faults” like some other persistent data frameworks.

In this version, opening a single Realm file on multiple threads now shares a single memory mapping of the file for all threads, significantly reducing the virtual memory required to work with large files.

Improved Multi-Process Crash Handling

Crashing while in the middle of a write transaction no longer blocks other processes from performing write transactions on the same file.

You’ll recall from our previous posts on Fast Inter-Process Communication and 0.91 release announcement that Darwin doesn’t support robust inter-process mutexes 😰. So we reimplemented some of Realm’s most fundamental locking mechanisms to use fcntl(3) to emulate robust inter-process mutexes on platforms that do not support the full POSIX API for them.

This change prevents a situation where a crash in one process holding the lock, while leaving the database locked in all other processes.

Enhancements

We greatly improved the performance of the background worker for fine-grained notifications for complex object graphs, and the performance of refreshing a Realm (including via autorefresh) when there are live Results/RLMResults objects for that Realm.

Bugfixes

We fixed a crash when an RLMArray or List object is destroyed from the wrong thread.


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.90 — Better Date and API Cleanup!

by /

We just released a new version of Realm Java to this website and to Bintray. This release adds full support for the Date datatype as well as an API cleanup.

Better Date support

Realm Java has from the beginning supported the standard java.util.Date, with one limitation. We truncated all timestamps to the nearest second.

The reason was that we wanted all of our products to be compatible, even though their date formats differ widely. Starting with Realm Java 0.90 and Realm Objective-C & Swift 0.101, we have fixed these issues and Realm Java now supports the full millisecond precision that is normally offered by the Date class.

This change will require an upgrade of the format of the Realm file, but it will happen automatically when opening a Realm file using 0.90+. Enjoy all those milliseconds :D

Android Adapters

We have decided to split off all Android-specific components into their own repository. This will make it easier to release enhancements and hotfixes for those as well as keeping the general size of the main library down.

This means that from 0.90, the class RealmBaseAdapter is no longer part of the main Realm library, and you will have to add the following dependency to get it:

dependencies {
	compile 'io.realm:android-adapters:1.0.1'
}

Going forward we are planning to add more Android framework support like RecyclerView and Cursors, but if you have any other ideas or feedback, please create an issue in the new Realm Android Adapters repository.

API Cleanup

Realm Java has been in beta for roughly 1.5 years, and during that time we have gotten a lot of feedback and input on how the API should look. For that reason we are now taking the opportunity to do a general cleanup. We are removing things that are not really used and improving others.

The most important items are below:

  • All Realm classes are now final.

  • RealmChangeListeners now send the changed object as a parameter to onChange().

realm.addChangeListener(new RealmChangeListener<Realm>() {
	@Override
	public void onChange(Realm realm) {
		// A reference to Realm. Note that all Realm instances and objects
		// are live objects, so this is just convenience and it cannot
		// be compared to previous references as they will all be the same.
    }
});

Person p = realm.where(Person.class).findFirst();
p.addChangeListener(new RealmChangeListener<Person>() {
	@Override
	public void onChange(Person person) {
		person.getName(); // The updated person.
	}
});
  • All query methods on Realm and DynamicRealm have been deprecated. All query methods should be done through Realm.where(), DynamicRealm.where() or RealmCollection.where().

  • RealmConfiguration.Builder.setModules() has been renamed to RealmConfiguration.Builder.modules().

  • Realm.refresh() has been deprecated in favor of Realm.waitForChange(). See this gist for an example of how to use it. This change was motivated by the fact that one-time tasks should either use the asynchronous API’s or open a Realm instance and close it again when done with it. waitForChange() is more suited for use-cases where you can’t use the async API (because it requires a Looper thread).

calling waitForChange() will block the current Thread until a commit happens in the background or you call stopWaitForChange(), which will stop the wait of the Thread that called waitForChange().

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.99 – Fine-Grained Notifications!

by /

We’ve released version 0.99 of Realm Objective‑C and Realm Swift!

This release adds the number one requested feature since our launch nearly two years ago: fine-grained change notifications.

We’ve also walked through the entire Objective-C and Swift APIs to clean up some unnecessary duplication and omissions. These make up several small breaking changes, but we hope you’ll find it makes the API more cohesive.

Fine-Grained Notifications

This release extends the collection notifications functionality we introduced in Realm 0.98 by adding a new changes parameter to the notification block.

This RLMCollectionChange/RealmCollectionChange parameter describes what changes have occurred at a fine-grained level, including the indices of objects that have been inserted, deleted, or modified since the last notification. This makes it possible to discretely control the animations and visual updates made to the content inside your UI, instead of arbitrarily reloading everything each time a notification occurs.

The arrays of indices follow UITableView’s batching conventions, and can be passed as-is to a table view’s batch update methods after converting to index paths in the appropriate section. Here it is in action:

Fine-Grained Notifications

For example, for a simple one-section table view, you can do the following:

notificationToken = results.addNotificationBlock { (changes: RealmCollectionChange) in
  switch changes {
  case .Initial:
    // Results are now populated and can be accessed without blocking the UI
    self.tableView.reloadData()
    break
  case .Update(_, let deletions, let insertions, let modifications):
    // Query results have changed, so apply them to the UITableView
    self.tableView.beginUpdates()
    self.tableView.insertRowsAtIndexPaths(insertions.map { NSIndexPath(forRow: $0, inSection: 0) },
        withRowAnimation: .Automatic)
    self.tableView.deleteRowsAtIndexPaths(deletions.map { NSIndexPath(forRow: $0, inSection: 0) },
        withRowAnimation: .Automatic)
    self.tableView.reloadRowsAtIndexPaths(modifications.map { NSIndexPath(forRow: $0, inSection: 0) },
        withRowAnimation: .Automatic)
    self.tableView.endUpdates()
    break
  case .Error(let error):
    // An error occurred while opening the Realm file on the background worker thread
    fatalError("\(error)")
    break
  }
}
__weak typeof(self) weakSelf = self;
self.notificationToken = [[Person objectsWhere:@"age > 5"] addNotificationBlock:^(RLMResults<Person *> *results, RLMCollectionChange *change, NSError *error) {
  if (error) {
    NSLog(@"Failed to open Realm on background worker: %@", error);
    return;
  }

  UITableView *tableView = weakSelf.tableView;
  // Initial run of the query will pass nil for the change information
  if (!changes) {
    [tableView reloadData];
    return;
  }

  // Query results have changed, so apply them to the UITableView
  [tableView beginUpdates];
  [tableView deleteRowsAtIndexPaths:[changes deletionsInSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  [tableView insertRowsAtIndexPaths:[changes insertionsInSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  [tableView reloadRowsAtIndexPaths:[changes modificationsInSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  [tableView endUpdates];
}];

See our docs on Collection Notifications for more information.

API Revisions

Over time, as we add new features to Realm, we need to take a step back, reviewing the entire API structure to adjust interfaces in a holistic way.

The changes can be summarized in these categories:

  1. RLMNotificationToken/NotificationTokens now only have one method to unsubscribe from notifications (-stop).
  2. Methods that had variants with and without an encryptionKey parameter have been combined.
  3. Properties that were present on both RLMRealm/Realm and RLMRealmConfiguration/Realm.Configuration have been deprecated in favor of the ones on the configuration.
  4. Methods and properties dealing with string-based Realm file paths now use NSURLs to better align with recent changes in Apple’s Foundation APIs.
  5. One Swift API we had missed in our Swift 2 transition has now shed its NSErrorPointer parameter and uses Swift’s native error handling mechanism (throws).

Here’s the complete list of Objective-C APIs that have been deprecated in favor of newer or preferred versions:

Deprecated API New API
-[RLMRealm removeNotification:] -[RLMNotificationToken stop]
RLMRealmConfiguration.path RLMRealmConfiguration.fileURL
RLMRealm.path RLMRealmConfiguration.fileURL
RLMRealm.readOnly RLMRealmConfiguration.readOnly
+[RLMRealm realmWithPath:] +[RLMRealm realmWithURL:]
+[RLMRealm writeCopyToPath:error:] +[RLMRealm writeCopyToURL:encryptionKey:error:]
+[RLMRealm writeCopyToPath:encryptionKey:error:] +[RLMRealm writeCopyToURL:encryptionKey:error:]
+[RLMRealm schemaVersionAtPath:error:] +[RLMRealm schemaVersionAtURL:encryptionKey:error:]
+[RLMRealm schemaVersionAtPath:encryptionKey:error:] +[RLMRealm schemaVersionAtURL:encryptionKey:error:]

Here’s the complete list of Swift APIs that have been deprecated in favor of newer or preferred versions:

Deprecated API New API
Realm.removeNotification(_:) NotificationToken.stop()
Realm.Configuration.path Realm.Configuration.fileURL
Realm.path Realm.Configuration.fileURL
Realm.readOnly Realm.Configuration.readOnly
Realm.writeCopyToPath(_:encryptionKey:) Realm.writeCopyToURL(_:encryptionKey:)
schemaVersionAtPath(_:encryptionKey:error:) schemaVersionAtURL(_:encryptionKey:)

Other Breaking Changes

  • Deprecate properties of type id/AnyObject. This type was rarely used, rarely useful, and unsupported in every other Realm product.
  • The block for -[RLMArray addNotificationBlock:] and -[RLMResults addNotificationBlock:] now takes another parameter, as explained above in the Fine-Grained Notifications section.

Bug Fixes

  • Fix a use-after-free when an associated object’s dealloc method is used to remove observers from an RLMObject.
  • Fix a small memory leak each time a Realm file is opened.
  • Return a recoverable RLMErrorAddressSpaceExhausted error rather than crash when there is insufficient available address space on Realm initialization or write commit.

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.100 – Queryable, Live Inverse Relationships!

by /

We’re releasing version 0.100 of Realm Objective‑C and Realm Swift today, adding another highly requested feature: making inverse relationships queryable and as live as their forward counterparts.

Queryable, Live Inverse Relationships

Let’s recap how relationships work in Realm. Relationships are unidirectional, and are declared using RLMArray/List or object properties. These properties can be used in queries, and are updated automatically to reflect changes to the property value made elsewhere in your app. Realm has historically provided a method to retrieve a snapshot of all objects that link to a specific object instance at the current point in time. Realm 0.100 improves on this by allowing you to declare linking objects properties that represent the inverse side of a relationship. These properties are live, auto-updating, queryable collections that provide the full capabilities of Realm’s other collection types. Unlike other Realm properties, linking objects properties cannot be modified directly. They’re modified automatically as a result of adding or removing the object from the RLMArray/List or object property that makes up the forward side of the relationship.

One-to-Many Relationships

@interface Dog : RLMObject
@property NSString *name;
@property NSInteger age;
@property Person *owner;
@end

@implementation Dog
@end

@interface Person : RLMObject
@property NSString *name;
@property NSInteger age;
@property (readonly) RLMLinkingObjects<Dog *> *dogs;
@end

@implementation Person
+ (NSDictionary *)linkingObjectsProperties {
    return @{
        @"dogs": [RLMPropertyDescriptor descriptorWithClass:Dog.class propertyName:@"owner"],
    };
}
@end
class Dog: Object {
    dynamic var name = ""
    dynamic var age = 0
    dynamic var owner: Person?
}

class Person: Object {
    dynamic var name = ""
    dynamic var age = 0
    let dogs = LinkingObjects(fromType: Dog.self, property: "owner")
}

Many-to-Many Relationships

@interface Person : RLMObject
@property NSString *name;
@property NSInteger age;
@property RLMArray<Person *><Person> *children;
@property (readonly) RLMLinkingObjects<Person *> *parents;
@end

@implementation Person
+ (NSDictionary *)linkingObjectsProperties {
    return @{
        @"parents": [RLMPropertyDescriptor descriptorWithClass:Person.class propertyName:@"children"],
    };
}
@end
class Person: Object {
    dynamic var name = ""
    dynamic var age = 0
    let children = List<Person>()
    let parents = LinkingObjects(fromType: Person.self, property: "children")
}

Note that due to their computed nature, RLMLinkingObjects/LinkingObjects properties must be declared as readonly/let.

The new linking objects properties offer several significant advantages over the previous approach:

1) Linking Objects Are Live, Auto-updating Collections

Just like the other collection types in Realm, RLMLinkingObjects/LinkingObjects are live and auto-updating. When new relationships are formed with or removed from the object, the linking objects will update to reflect the currently linking objects. This means you are no longer working with a static point-in-time snapshot of the relationship that you need to keep updated yourself.

2) Linking Objects Can Be Used In Queries

To perform queries on linking objects with the old API you had to manually filter the objects in your own code, missing out on the performance & liveness provided by Realm’s native query system.

Linking objects properties are completely integrated with Realm’s query system, making it efficient and easy to filter over inverse relationships.

// People that have a child that have a parent named Diane.
[PersonObject objectsWhere:@"ANY children.parents.name == 'Diane'"];

// People whose parents have an average age of > 65.
[PersonObject objectsWhere:@"[email protected] > 65"];
// People that have a child that have a parent named Diane.
realm.objects(Person).filter("ANY children.parents.name == 'Diane'")

// People whose parents have an average age of > 65.
realm.objects(Person).filter("[email protected] > 65")

3) Linking Objects Are Realm Collections

While the previous linking objects API returned a standard library array type, the new RLMLinkingObjects/LinkingObjects types conform to Realm’s collection type protocol. This makes them familiar to work with and provides all the functionality you’re used to from Realm’s RLMResults/Results types.

// Which of my parents are over the age of 56?
[self.parents objectsWhere:@"age > 56"];

// Calculate the age of my parents.
[self.parents averageOfProperty:"age"];
// Which of my parents are over the age of 56?
self.parents.filter("age > 56")

// Calculate the age of my parents.
self.parents.average("age")

Deprecations

The -[RLMObject linkingObjectsOfClass:forProperty:] and Object.linkingObjects(_:forProperty:) methods are deprecated and will be removed in a future release.

Other Changes

  • Queries that compare objects for equality now support multi-level key paths.
  • Queries that compare RLMArray / List properties using != now give the correct results.
  • Fix an assertion failure when a second write transaction is committed after a write transaction deleted the object containing an RLMArray/List which had an active notification block.

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.89 — Model and Collection interfaces!

by /

We just released a new version of Realm Java to this website and to Bintray. This release is packed with fixes and new features.

RealmModel interface

A longstanding requirement for Realm has been that all Realm model classes must extend the base class RealmObject.

Starting with 0.89, this is no longer a strict requirement and you can now choose to implement the new RealmModel interface instead.

@RealmClass
public class implements RealmModel {
	
}

You will need to manually add the @RealmClass annotation since inheriting annotations from interfaces is not yet supported by Android.

The helper methods on RealmObject are available as static methods, so if you use RealmModel you can use these methods.

Person person = getPerson();

// Extending RealmObject
person.isValid();
person.addChangeListener(listener);

// Implementing RealmModel
RealmObject.isValid(person);
RealmObject.addChangeListener(person, listener);

Extending RealmObject is still the recommended approach, but you now have the option of using the method which suits your architecture and codebase guidelines better.

Note that Realm Java still does not support extending anything other than RealmObject. That feature is still being tracked here.

RealmCollection API

The Realm Java API currently consists of two collections: RealmResults and RealmList, which both implement the standard List interface.

Both of these classes have been extended with additional Realm capabilities, but unfortunately their behavior had diverged slightly, which caused problems with RealmBaseAdapter.

In order to provide a more consistent experience, we are now introducing two new interfaces: RealmCollection and OrderedRealmCollection.

This provides a solid foundation for adding future collections as well as unifying the behavior and naming of methods across the API.

It has a few implications:

The behavior of methods like remove and clear now only operate on the collection and not the underlying Realm data. This especially impacts RealmResults where these methods will now throw UnsupportedOperationException.

  • RealmBaseAdapter now works out of the box with both RealmList and RealmResults.

  • Methods for deleting objects from both the collection and Realm are now called deleteFromRealm() or deleteAllFromRealm().

  • Realm.clear(Class) and Realm.clear() have been renamed to Realm.delete(Class) and Realm.deleteAll().

  • RealmObject.removeFromRealm() has been renamed to RealmObject.deleteFromRealm().

Stable iterators

One of the design paradigms of Realm is the concept of auto-updating results. Normally that is a great feature to have, except in one case: Changing objects in a way that would remove them from the RealmResult.

Take the following example:

RealmResults<Person> results = realm.where(Person.class).equalTo("inviteToGoogleIO", false).findAll();

// Try to invite all the people
realm.beginTransaction();
for (Person p : results) {
	p.inviteToGoogleIO(true);
}
realm.commitTransaction();

With a normal collection, you would expect to have all persons invited to Google I/O, but due to RealmResults being live-updated, it would actually only send invites to every other person. The reason is that due to the RealmResults live-updating, it would adjust the size of the collection the moment you set the first boolean field to true. This would in turn cause the iterator’s internal index to point to the next item (which hasn’t been updated), so when you call Iterator.next() or similar, it would skip over an item.

The solution so far has been to iterate backwards as that takes into account the changing size():

for (int i = results.size() - 1; i >=0; i--) {
	results.get(i).inviteToGoogleIO(true);
}

This is however very counter-intuitive. With 0.89, the auto-updating feature of RealmResults have changed slightly so instead of RealmResults being live all the time, they are now only updated on Looper events.

This means that iterators will now work as expected but also introduces a slight chance that you might accidentally access a deleted item.

RealmResults<Person> results = realm.where(Person.class).findAll();
for (Person p : results) {
	p.deleteFromRealm(); // Indirectly delete all items one-by-one.
}

// RealmResults are not updated until next Looper event
// So the RealmResult might now contain deleted objects
Person p = results.get(0); 
p.isValid() == false;

// Deleting the item directly on the RealmResults will remove them
// from the RealmResults as well
results.deleteFromRealm(0);

// and new Queries will also exclude deleted objects
results = realm.where(Person.class).findAll(); // Deleted users are removed

Read more here.

This change also impacts all RealmChangeListeners that were previously triggered after each call to Realm.commmitTransaction() on the same thread. They are now deferred to the next Looper event just like changes from other threads. This should have no effect on normal app behavior, but could potentially cause issues in unit tests that assumed that callbacks where immediately notified.

Breaking changes 🚨

PrimaryKey fields are no longer automatically marked as @Required. They can now be null if the type of the field can usually be null.

This change will throw a RealmMigrationNeededException. Either manually add @Required to the primary field to maintain the same behavior as 0.88.3 and below, or change the nullability in a migration step.

RealmObjectSchema personSchema = schema.get("Person");
personSchema.setNullable("myPrimaryKey", true);

Other improvements

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