持久化方案-Reaml数据库简介

一、Realm官网地址:https://realm.io/cn/
二、Realm框架介绍:
    realm是一个跨平台移动数据库引擎,支持iOS、OS X(Objective-C和Swift)以及Android;
    核心数据引擎C++打造,并不是建立在SQLite之上的ORM, 是拥有独立的数据库存储引擎;
    比sqlite, coredata效率更快、简单易用。
三、Realm辅助工具:
    1、RealmBrowser:可视化访问Realm数据库(AppStore中可下载)
    2、Xcode插件:reaml-cocoa可以快速创建Realm可存储模型对象
      (https://github.com/realm/realm-cocoa)
四、Realm支持的数据类型:
    BOOL, bool, int, NSInteger, long, long long, float, double, NSString, NSDate, NSData, and NSNumber
    注意:不支持集合类型 
    解决方案:序列化成NSData进行存储 或 转换成RLMArray<RLMObject>进行存储(麻烦)
五、Realm数据库:
    1. 用户机制:不同的用户, 使用不同的数据库
      + (void)setDefaultRealmForUser:(NSString *)username {
            RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
            // 使用默认的目录,但是使用用户名来替换默认的文件名
            config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:username] URLByAppendingPathExtension:@"realm"];  
            // 将这个配置应用到默认的 Realm 数据库当中
            [RLMRealmConfiguration setDefaultConfiguration:config];
       }

    2. 只读方式打开数据库:config.readOnly = YES;

    3. 数据库文件删除:需要删除数据库文件以及辅助文件(官方要求)
       NSFileManager *manager = [NSFileManager defaultManager];
       RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
       NSArray<NSURL *> *realmFileURLs = @[config.fileURL, 
                                          [config.fileURL URLByAppendingPathExtension:@"lock"], 
                                          [config.fileURL URLByAppendingPathExtension:@"log_a"],
                                          [config.fileURL URLByAppendingPathExtension:@"log_b"],
                                          [config.fileURL URLByAppendingPathExtension:@"note"]
                                          ];
       for (NSURL *URL in realmFileURLs){  
            NSError *error = nil; 
           [manager removeItemAtURL:URL error:&error];
           if(error){//处理错误}
       }
六、Realm增删改查:首先创建数据模型, 必须继承自RLMObject
    6.1 创建对象的方式:1. 普通创建
                     2. 通过父类RLMObject中的方法快速创建:initWithValue(数组或字典)
                        请注意:跟属性顺序需保持一致;
                        所有的必需属性都必须在对象添加到Realm前被赋值;
                        由于Realm在自己的引擎内部有很好的语义解释系统,
                        所以 Objective‑C 的许多属性特性将被忽略,
                        如nonatomic, atomic, strong, copy 和 weak 等,
                        因此为了避免误解,官方推荐在编写数据模型的时候不要使用任何的属性特性。
    6.2 简单的数据操作:
                     1. 保存指定模型:
                        获取RLMRealm对象:RLMRealm *realm = [RLMRealm defaultRealm];
                        方式1:开启写入事务:[realm beginWriteTransaction];
                              添加模型对象:[realm addObject:stu];
                              提交写入事务:[realm commitWriteTransaction];

                        方式2:[realm transactionWithBlock:^{
                                   [realm addObject:stu];
                              }];

                        方式3:[Stu createInRealm:realm withValue:@{@"stu_id": @22, @"name": @"马冬梅2", @"age": @666}];

                     2. 更新指定模型
                        方式1:在事务中直接更新对象
                              [realm beginWriteTransaction];
                              stu.name = @"土豆";
                              [realm commitWriteTransaction];

                        方式2:根据主键进行更新
                              1. 要求操作的模型, 必须实现方法
                                 + (NSString *)primaryKey 返回主键
                              2. 在事务中调用方法:[realm addOrUpdateObject:stu2];

                        方式3:根据主键进行更新
                              1. 要求操作的模型, 必须实现方法
                                 + (NSString *)primaryKey 返回主键
                              2. 在事务中调用方法:
                                 [Stu createOrUpdateInRealm:realm withValue:@{@"stu_id": @22, @"name": @"马冬梅2", @"age": @666}];

                      3. 使用RLMRealm对象, 在事务中删除数据
                        方式1:删除指定的对象,
                              注意: 必须是从realm数据库中获取的模型对象, 而不是自己创建的
                              RLMObject *obj = [realm objectWithClassName:@"Stu" forPrimaryKey:@2];
                              [realm deleteObject:obj];
                     
                        方式2:删除所有对象
                              [realm deleteAllObjects];

                     4. 使用RLMRealm对象, 查询数据
                       注意事项:1. 所有的查询(包括查询和属性访问)在Realm中都是延迟加载的,
                               只有当属性被访问时,才能够读取相应的数据;
                               2. 查询结果并不是数据的拷贝:
                               修改查询结果(在写入事务中)会直接修改硬盘上的数据;
                               3. 一旦检索执行之后, RLMResults将随时保持更新。

                       查询所有:[Stu allObjects]

                       条件查询:RLMResults<Stu *> *stus = [Stu objectsWhere:@"name = '马冬梅'"];

                       排序查询:[stus sortedResultsUsingProperty:@"name" ascending:YES];

                       链式查询:在查询结果的基础上, 进行二次查询
                               [stus objectsWhere:@"address beginswith '北京'"];

                       分页查询:查询出来的结果对象是懒加载, 只有真正访问时, 
                               才会加载相应对象, 所以这里的分页, 其实就是从所有集合中分页获取即可
                               RLMResults<Dog *> *dogs = [Dog allObjects];
                               for (NSInteger i = 0; i < 5; i++) {
                                    Dog *dog = dogs[i];
                                    // …
                               }
七、Realm关系:
    7.1 对一关系:当一个对象持有另外一个对象时, 比如人有一个宠物🐶
    7.2 对多关系:1. 在Dog中, 遵循指定协议方法
                   RLM_ARRAY_TYPE(Dog):
                   RLM_ARRAY_TYPE 宏创建了一个协议,从而允许 RLMArray<Dog> 语法的使用
                2. 在Person中, 定义属性:
                   @property (nonatomic, strong) RLMArray<Dog *><Dog> *dogs;
                   虽然可以给 RLMArray 属性赋值为 nil,
                   但是这仅用于“清空”数组,而不是用以移除数组。
                   这意味着您总是可以向一个 RLMArray 属性中添加对象,
                   即使其被置为了 nil。
                   Person属性意义解释:RLMArray: 属性类型。
                                    <Object *>: 属性的特别化(generic specialization),
                                                这可以阻止在编译时使用错误对象类型的数组。
                                    <Object>: 此RLMArray遵守的协议,
                                                可以让 Realm 知晓如何在运行时确定数据模型的结构。
    7.3 反向关系:人拥有狗, 狗又有相应的主人?
                1. Dog中定义属性:@property (readonly) RLMLinkingObjects *master;
                2. 实现协议方法, 标明链接关系:
                   + (NSDictionary<NSString *,RLMPropertyDescriptor *> *)linkingObjectsProperties {
                         return @{
                                 @"master": [RLMPropertyDescriptor descriptorWithClass:NSClassFromString(@"Stu") propertyName:@"dogs"]
                                 };
                   }
八、可空属性&默认值&忽略属性:
    默认情况下, 属性值可空, 如果强制要求某个属性非空, 可以使用如下方法
    8.1 设置属性不能为nil:+ (NSArray *)requiredProperties;
        特点:如果再次赋值为nil, 则会抛出异常错误
    8.2 设置属性默认值:+ (NSDictionary *)defaultPropertyValues;
    8.3 设置可忽略属性:+ (NSArray *)ignoredProperties;
    开发经验:可以借助忽略属性&只读属性打造计算属性, 完成集合以及UIImage对象的存储与获取
九、Realm数据库通知:
    数据库和结果集都可添加通知;Realm实例将会在每次写入事务提交后,
                           给其他线程上的Realm实例发送通知;必须持有返回的token
    9.1 获取Realm通知:
        self.token = [realm addNotificationBlock:^(NSString *notification, RLMRealm * realm) {
                        // 接收到更改通知, 需要做的事情
                      }];
    9.2 移除通知:[self.token stop];
十、Realm数据库迁移:
    10.1 数据结构的迁移:
         // 在 [AppDelegate didFinishLaunchingWithOptions:] 中进行配置
         RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
         // 设置新的架构版本。
         // 这个版本号必须高于之前所用的版本号
         //(如果您之前从未设置过架构版本,那么这个版本号设置为 0)
         config.schemaVersion = 1;
         // 设置闭包,这个闭包将会在打开低于上面所设置版本号的 Realm 数据库的时候被自动调用
         config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
                // 目前我们还未进行数据迁移,因此 oldSchemaVersion == 0
                if (oldSchemaVersion < 1) {
                // 什么都不要做!
                // Realm 会自行检测新增和需要移除的属性,然后自动更新硬盘上的数据库架构
                }
         };
         // 告诉 Realm 为默认的 Realm 数据库使用这个新的配置对象
         [RLMRealmConfiguration setDefaultConfiguration:config];
         // 现在我们已经告诉了 Realm 如何处理架构的变化,打开文件之后将会自动执行迁移
         [RLMRealm defaultRealm];

    10.2 数据的迁移:
         // enumerateObjects:block: 方法遍历了存储在 Realm 文件中的每一个“Person”对象
         [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
               // 将名字进行合并,存放在 fullName 域中
               newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
                                                  oldObject[@"firstName"],
                                                  oldObject[@"lastName"]];
         }];

     10.3 属性重命名:
         [migration renamePropertyForClass:Person.className oldName:@"yearsSinceBirth" newName:@"age"];

     10.4 多版本增量式迁移:根据数据库版本的不同,修改成最新版本(注意不要丢失数据)
          // enumerateObjects:block: 遍历了存储在 Realm 文件中的每一个“Person”对象
          [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
                  // 只有当 Realm 数据库的架构版本为 0 的时候,才添加 “fullName” 属性
                  if (oldSchemaVersion < 1) {
                         newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
                                                            oldObject[@"firstName"],
                                                            oldObject[@"lastName"]];
                  }
          // 只有当 Realm 数据库的架构版本为 0 或者 1 的时候,才添加“email”属性
          if (oldSchemaVersion < 2) {
                newObject[@"email"] = @"";
          }
          }];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容