Realm Platform: Chat Demo

 

Realm Platform

The best way to show off Realm Platform is to actually do some coding! We don’t normally make this demo available, but it’s good at highlighting some cool features.

I’ll be using a SlackTextViewController, which is Slack’s messaging UI for their iOS app. I’ll integrate Realm into it, and by virtue of how Realm’s APIs work with Realm Platform, it’ll automatically start syncing. In the end, we’ll have a very simple messaging app.

Setup

I have an Ubuntu instance running on DigitalOcean. It takes about five minutes to set up, but most of that time is just provisioning the server. When you get it running, you have to create an admin user. The dashboard shows some basic metrics, and then you can go in and add users. I created a demo user to use in the example.

I have two versions of Xcode running in order to speed things up. The first is an unaltered version of the example app that Slack includes. At first, the app writes dummy data into the messaging history.

On the second version, we’re working with the Message object, which appears as it does out of the box, as an NSObject:

Get more development news like this

@interface Message : NSObject

If you go into the MessageViewController, the TableView is backed by an NSMutableArray.

@property (nonatomic, strong) NSMutableArray *messages;

There are really only two methods that actually do anything. The first is configureDataSource, which creates some dummy data and sets it as the default data in the message array. The other one is the didPressRightButton, which is where we create the Message object and insert it into the array, then update the TableView.

Optimizing for Realm

I want to turn this into a Realm-optimized app.

Message Object

I’ll start with the Message object itself. Instead of an NSObject, I’ll change it to be an RLMObject.

@interface Message : RLMObject

There are two string properties, but I want to add an additional property: dateCreated. I want to be able to query the Realm and sort it by the date that it’s created.

@property NSString *username;
@property NSString *text;
@property NSDate *dateCreated;

I’ll also import the Realm framework on the ViewController…:

#import <Realm/Realm.h>

…and I’ll change the Message array to be in RLMResults, such that I can query Realm and retrieve all the Message objects in it:

@property (nonatomic, strong) RLMResults *messages;

@property (nonatomic, strong), RLMNotificationToken *token;

I’ve got RLMResults, which is the messages, and RLMNotificationToken.

Realm supports a reactive architecture, so you can observe changes in the Realm. We offer a number of different notifications: you can get notifications when the Realm updates, and you can also get notifications that tell you more specifically what changed. This is very popular on iOS in particular, using the NSFetchedResultsController to see the animated changes. We now support passing those change-sets.

In configureDataSource, I switch out the code to work off of Realm:

self.messages = [[Message allObjects]
    sortedResultsUsingProperty:@"dateCreated" ascending:NO];

self.token = [self.messages addNotificationBlock:^(RLMResults * _Nullable results,
                                                   RLMCollectionChange * _Nullable change,
                                                   NSError * _Nullable error) {
    [self.tableView reloadData];
}];

I get all the objects out of the Realm that are messages, then I sort that by the dateCreated property. After, there is the notification block, where I listen to the Realm, and as it updates, it reloads the TableView.

To note, this is all standard Realm API today. Since this is a synchronized Realm, this notification is also acting as the notification for synchronized changes, and the framework includes the ability to connect to the Realm Object Server. Changes are automatically integrated on a background thread.

That same notification functionality can power your UI to update, not just in response to local changes that are happening on other threads, but also from remote changes that are potentially happening on the server or on other devices.

didPressRightButton

I need to add the ability to set the dateCreated property, so I can sort by that. This will fit with Realm’s ACID compliance, where everything is done through transactions:

[self.tableView beginUpdates];
[self.messages.realm transactionWithBlock:^{
    [self.messages.realm addObject:message];
}];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation: rowAnimation];
[self.tableView endUpdates];

Whatever changes you apply, they will apply atomically across the different devices that are synchronized.

Synchronizing

To make this a synchronized Realm, I need to change the configuration for the default Realm, because I’m now querying for the messages that are in the default Realm. The first part in creating a synchronized Realm is getting a credential.

In viewDidLoad, I’ll add:

// The auth server URL
NSURL *authURL = [NSURL URLWithString:@"http://45.55.17.84:9080"];

// Creating a debug credential since this demo is just using the generated access token
// produced when running the Realm Object Server via the `start-object.server.command`
RLMSyncCredential *credential = [RLMSyncCredential credentialWithUsername:@"[email protected]"

                                              password:@"demo"
                                              actions:RLMAuthenticationActions UseExistingAccount];

Typically, you would have a UI where the user would enter in the username and password. For simplicity’s sake, since all I’m doing is setting the URL for the authentication server so the Realm Object Server includes authentication in it, I use the IP I already have running on DigitalOcean, and then I create a credential with a username and password.

With the credential, the next part is logging in. There’s a method on RLMSyncUser where I would call authenticateWithCredential, using the credential that I created. I pass in the authentication URL, and then in the callback I’ll either get an error or I’m going to get a RLMSyncUser. This user is now an authenticated user, if it was successful.

The final step is taking that authenticated user and the sync URL to the actual Realm that I want to synchronize. I create a syncConfiguration and set it up on the RLMRealmConfiguration.

If you have ever customized your Realms instead of just using the default Realm, you would create an RLMRealmConfiguration. For example, you may want a read-only Realm. With the Realm Object Server, you have another configuration setting that you need to set, which is this syncConfiguration. That’s all based off having an authenticated user in the URL. I also move configureDataSource and configureActionItems into the callback.

It Works!

That’s it! With only about 20 lines of code, you can be up and running with a synchronized Realm. The rest is all the APIs that you’re hopefully enjoying already.

Next Up: Demo: Build a Reactive App Using the Realm Platform

General link arrow white

About the content

This content has been published here with the express permission of the author.


Adam Fish

Adam is the Director of Product at Realm, where he manages the product development for currently supported mobile platforms and upcoming new products. He has a strong background in entrepreneurship and software development, having previously co-founded Roobiq, a mobile-first sales productivity app used by sales teams worldwide.

4 design patterns for a RESTless mobile integration »

close