Realm -- oc版实践(下)

iOS 118 2017-11-07 22:44

前言

如果您对Realm 基础还没有很了解的话,请阅读Realm -- oc版使用(上)
上篇中,我们已经讲了Realm 的数据模型,增删改查基础操作。
接下来,我们就来说说项目实践中“踩坑”。

数据模型必须继承RLMObject

与数据库操作相关的model当然要继承RLMObject,不过,我们可以新建model,专门用来接收服务端数据,利用MJExtension等方法,model转化成RLMmodel后进行存储,model的继承就与RLMObject没有关系了,虽然model可以继承任意类型,但是如果有多个RLMmodel存在,就要实现多个model,文件增加,维护起来不方便。(有利有弊)

下图是上述思想的扩展,所有的数据库基础操作都在BaseDBModel中完成。

Realm -- oc版实践(下)-JEESNS
image.png
Realm不支持集合类型
  • 集合类型:NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSSet,NSMutableSet等。
    比如,服务端返回数据中存在字典,可以把字典中key提出来,新建一个RLMObject模型,与之前的模型创建关系,或者只能把字典转换成NSString或者NSData类型进行存储。
Realm的加密方案

在创建 Realm 数据库时采用64位的密钥对数据库文件进行 AES-256+SHA2 加密,通过设置encryptionKey 进行加密。

RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
NSString *path = [self db_currentRealmPath];
if (path) {
            configuration.fileURL = [NSURL fileURLWithPath:path];
}
#ifdef DEBUG
configuration.encryptionKey = nil;
#else
configuration.encryptionKey = [self db_getKey];
#endif
NSError *e = nil;
realm = [RLMRealm realmWithConfiguration:configuration error:&e];

以下是Realm的UI更新通知,项目中还未使用

Realm 通知

Realm 的写操作事务被提交之后,无论这个事务发生在何种线程或者何种进程之中,这个通知处理闭包都将会被触发:

// 获取 Realm 通知
token = [realm addNotificationBlock:^(NSString *notification, RLMRealm * realm) { 
  [myViewController updateUI];
}];// 随后
[token stop];

集合通知
包括:已插入对象已删除对象,或者已修改对象的索引,这三种操作的通知。
集合通知是异步触发的,首先它会在初始结果出现的时候触发,随后当某个写入事务改变了集合中的所有或者某个对象的时候,通知都会再次触发。

 // 观察 RLMResults 通知
  __weak typeof(self) weakSelf = self;
  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);
      return;
    }

    UITableView *tableView = weakSelf.tableView;
    // 对于变化信息来说,检索的初次运行将会传递 nil
    if (!changes) {
      [tableView reloadData];
      return;
    }

    // 检索结果被改变,因此将它们应用到 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];
  }];
  }

对象通知
Realm 支持对象级别的通知。
在此对象被删除时、被修改时获取相应的通知。

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 {
            
            [token stop];
            token = nil;
        }
        
    }];

UI更新通知

  • [RLMCollection addNotificationBlock:]
// Observe RLMResults Notifications
__weak typeof(self) weakSelf = self;
//self.notificationToken -- >RLMNotificationToken 
//self.collection -->id<RLMCollection> collection 对应返回的RLMResults
self.notificationToken = [self.collection addNotificationBlock:^(RLMResults<Item *> *results, RLMCollectionChange *changes, 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];
}];

- (void)insertItem {
  // Perform an interface-driven write on the main thread:
  [self.collection.realm beginWriteTransaction];
  [self.collection insertObject:[Item new] atIndex:0];
  // And mirror it instantly in the UI
  [tableView insertRowsAtIndexPaths:[NSIndexPath indexPathForRow:0 inSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  // Making sure the change notification doesn't apply the change a second time
  [self.collection.realm commitWriteTransactionWithoutNotifying:@[token]];
}

通过本次项目中使用realm开始学习,发现更多基础知识可以先从官方文档看起,然后循循渐进,通过阅读github相关资料的源码,更深入学习realm。

强烈推荐
Realm数据库 从入门到“放弃”
该文章还较详细的介绍了从其他数据库迁移到Realm中的问题,还有其他realm的优缺点,很赞。

有意见或建议请评论留言,新人写技术文章,谢谢大家指正。

文章评论