Chat Realm, Mobile Cross-Platform Database

Keywords: Database Mobile iOS Java

Author|Qian Kai

Almond Mobile Development Engineer, former Embedded Engineer, focuses on the new trend of big front-end technology.

During the development of Almond App, we tried out the very popular mobile database, Realm, in relatively independent modules, which is challenging and surprising.Following is an example of iOS(Object-C) platform, briefly introduces the basic use of Realm, and summarizes the experience.

What is Realm

Realm is a cross-platform, cross-language data storage solution developed for mobile.It's handy, powerful, rich and constantly updated.Realm supports Java, JS,.NET, Swift, OC in language, basically covering all scenarios on the current mobile side.

At present, Realm is fully open source, and there are many three-party plug-ins available, so the ecology is relatively mature.

To configure
Realm is easy to configure, and upgrades and data migration are intuitive, but note that:

Each update to a database table must manually increase the version number or it will flip back.

Upgrading a table (adding or deleting fields or tables) does not require handwritten migration code; if there are advanced operations such as data migration, modifying field names, merging fields, data upgrade, etc., write the code in the block, referencing the documentation.

Generally speaking, all version branches of a full recursive upgrade should be written and cleaned up for each version in order to avoid accidents (e.g. field A was deleted from version 2 compared to version 1, version 3 was added back, users would have dirty data if they upgraded directly from version 1 to version 3).

Start the basic process of Realm:

    // 1. Configuration database file address
    NSString *filePath = path;
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    config.fileURL = [[[NSURL URLWithString:filePath] URLByAppendingPathComponent:@"YF"] URLByAppendingPathExtension:@"realm"];

    // 2. Encryption
    config.encryptionKey = [self getKey];
    // 3. Set the version number (you should increase it every time you publish)
    config.schemaVersion = 1;
    // 4. Data Migration
    config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
        if (oldSchemaVersion < 1) {
            // do something
    // 5. Set configuration options
    [RLMRealmConfiguration setDefaultConfiguration:config];
    // 6. Start the database and complete the configuration
    [RLMRealm defaultRealm];

Building tables
Classes that directly inherit RLMObject will automatically create a table whose items are attributes of the class.A few points to note:

Types such as Number, BOOL, etc. use the format specified by Realm.

Array uses an RLMArray container to represent a one-to-many relationship.

You can operate as a normal Object before it is repositioned; however, objects after it is repositioned or query are processed according to Realm's specifications.This requires special attention when you are new to it.

A typical Realm object:

@interface YFRecommendHistoryObject : RLMObject

@property (nonatomic) NSNumber<RLMInt> *recommendId;
@property (nonatomic) NSNumber<RLMInt> *patientId;

@property (nonatomic) NSString *patientName;
@property (nonatomic) NSNumber<RLMInt> *created;

@property (nonatomic) NSString *createdTimeString; // yyyy-MM-dd hh:mm

@property (nonatomic) NSNumber<RLMInt> *count;
@property (nonatomic) NSNumber<RLMInt> *totalPrice; ///<Total Price, Points

@property (nonatomic) NSString *totalPriceString; /// ï¿¥xxxx.xx
@property (nonatomic) RLMArray<YFRecommendDrugItem> *items;


All objects managed by Realm are thread insecure, and objects must never be accessed across threads or passed as parameters.The recommended practice is to re-query every thread, even every time an object needs to be accessed.

PS: The latest version of Realm provides some ways to transfer objects across threads (RLMThreadSafeReference).

Add, delete, check and change

// create object
Person *author = [[Person alloc] init];    = @"David Foster Wallace";

// Get Realm Object
RLMRealm *realm = [RLMRealm defaultRealm];

// Warehousing
[realm beginWriteTransaction];
[realm addObject:author];
[realm commitWriteTransaction];

In addition, assignment to one-to-one or one-to-many relationships is equivalent to warehousing.

All assignments, deletions, and other operations on the managed object must be placed in the begin-end pair, otherwise it is illegal and flips back directly.

// delete object
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];

It is important to note that if an object is deleted from the database, it is illegal and any access to it will result in an exception.

The syntax of the query is similar to NSPredicate.

// Use query string to query
RLMResults<Dog *> *tanDogs = [Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];

// Query using Cocoa's NSP redicate object
NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@",
                                                     @"tan", @"B"];
tanDogs = [Dog objectsWithPredicate:pred];

Do not manually manage notifications for database object updates. Realm automatically synchronizes data for each thread in Runloop, but the timing of synchronization is unexpected and the notification system that comes with the Realm framework should be used.

Notification of collection objects:

self.notificationToken = [[Person objectsWhere:@"age > 5"] addNotificationBlock:^(RLMResults<Person *> *results, RLMCollectionChange *changes, NSError *error) {
    if (error) {
      NSLog(@"Failed to open Realm on background worker: %@", error);

    UITableView *tableView = weakSelf.tableView;

    // Update related UI in callback
    [tableView beginUpdates];
    [tableView deleteRowsAtIndexPaths:[changes deletionsInSection:0]
    [tableView insertRowsAtIndexPaths:[changes insertionsInSection:0]
    [tableView reloadRowsAtIndexPaths:[changes modificationsInSection:0]
    [tableView endUpdates];

Realm achieves responsiveness in OC mainly in this way.On other language platforms (JS, JAVA, Swift), Realm has better support for responsive programming.

Notifications for common object s:

RLMStepCounter *counter = [[RLMStepCounter alloc] init];
counter.steps = 0;
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
[realm addObject:counter];
[realm commitWriteTransaction];

__block RLMNotificationToken *token = [counter addNotificationBlock:^(BOOL deleted,
                                                                      NSArray<RLMPropertyChange *> *changes,
                                                                      NSError *error) {
    if (deleted) {
        NSLog(@"The object was deleted.");
    } else if (error) {
        NSLog(@"An error occurred: %@", error);
    } else {
        for (RLMPropertyChange *property in changes) {
            if ([ isEqualToString:@"steps"] && [property.value integerValue] > 1000) {
                NSLog(@"Congratulations, you've exceeded 1000 steps.");
                [token stop];
                token = nil;


There are two points to note about the use of notifications:

The reference to token must be maintained and the token is released, which invalidates the notification (it is best to stop the token as specified before it is released).

object notifications do not listen for changes in the members of a collection property such as the LMArray that objects are received and need to be handled separately.

Some summaries
Is Realm really good?Realm is also a good choice for older sqlite s and Core Data with steep learning curves.However, as far as the current version is concerned, there are still some limitations.

Let's start with the advantages:

Simple: Start with the speed of light (and then walk on the pit at the speed of light, and APP blinks wildly).This is really a small team gospel. You don't need to learn Core Data with steep curves or even write sql. You can use it in a real project by simply reading the documentation below.Upgrade, migration and so on have very mature interfaces.

Excellent performance: A simple look at the principle, Realm uses memory-mapped Zero-Copy technology, which is an order of magnitude faster than the complex process of traditional database link-query-hit-memory copy-object serialization.It also uses git-like object versioning mechanism internally, with good concurrent performance and security.

Thread security: Realm denies cross-thread access to objects, while adding, deleting, and altering objects in different threads is absolutely safe.The cost of security is code inconvenience, which is described below.

Cross-platform: iOS and Android can share a set of storage schemes, while Realm databases can be easily migrated across different platforms.For RN development, Realm is the preferred database schema, which really does write once run everywhere.

Responsive: Realm's query results are updated in real time with changes in the database (requiring objects to be in the Run Loop thread), and with KVO or Realm's own ObjectNotification, it is easy to build a responsive UI that reflects changes in data instantly, which should be in harmony with the current mainstream Responsive Framework (ReactNative, ReactiveCocoa).But ask users to change their minds, or there will be a lot of weird bug s.

ORM: Although Realm claims to be a "full-featured database customized for mobile developers", it does contain many of the features of ORM. You don't need to write the middle layer manually, just take it out to be a fresh and lively object, everyone is happy.

Say hell again:

Database objects cannot be shared across threads: this is a requirement of Realm design, and cross-threaded access means that you can only re-query them yourself.As mentioned earlier, it's faster to get started and walk through a pit because of this: asynchronous blocks, callbacks to network interfaces, and notifications from different threads all trigger this access exception.ORM is the most critical object or the transformation of the way of thinking. Although it is ORM, it is still a database, the place of the query, or don't be lazy.

Database object management: There are many pits, such as direct exceptions when accessing a deleted object; all queried objects cannot be used after the database is close d; modifying the properties of the managed object must be done in the specified block or database transaction set, which is equivalent to database entry.Realm objects are indistinguishable from normal objects, so an important principle in using Realm is that database objects are not passed as parameters.

Code is heavily eroded: all database objects inherit the specified class (they cannot inherit their own base class), add, delete, and alter checks, and have special syntax requirements for query result processing, which incurs a high cost in introducing Realm into old projects or removing it from projects.

Static libraries are large and versions are unstable: introducing such a three-party static library will increase the size of the App and visually increase it by at least 1 M.In addition, Realm is not very stable at the moment. Previously, the new ObjectNotification function was tested and there were occasional bug s that could not get callbacks. Compared with the mature sqlite scheme, it is not very reassuring.

The following is a basic introduction to Realm Database, the main scenario being local storage on the mobile side.Realm also offers Realm Platform products and mobile responsive back-end solutions that interested teams can learn about.

All in all, Realm is a worth trying storage scheme.Realm is your first choice if you are looking for fast deployment, cutting-edge features, and cross-platform; if you are looking for stability and your existing projects are large and mature, you can choose to watch the technology progress temporarily and choose carefully.

Text Link

Service Recommendation

Posted by JDcrack on Sun, 28 Apr 2019 10:00:36 -0700