Realm -- oc版实践(下)

作者: JasonLee宸 | 来源:发表于2017-09-22 15:27 被阅读73次

    前言

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

    数据模型必须继承RLMObject

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

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

    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的优缺点,很赞。

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

    相关文章

      网友评论

        本文标题:Realm -- oc版实践(下)

        本文链接:https://www.haomeiwen.com/subject/lqpnsxtx.html