zoukankan      html  css  js  c++  java
  • iOS开发-Realm数据库

    Realm

    Realm-Object-c,见:
    https://realm.io/cn/docs/objc/latest/
    Realm官网:
    https://realm.io

    使用流程

    • 导入头文件#import < Realm/Realm.h >.
    • 创建类,继承于RLMObject.
    • 在类中生成数据模型.
    • 在需要的地方创建实例,使用Realm方法调用.

    数据模型

    创建简单数据模型

    简单地,继承RLMObject创建类,在.h中通过属性定义不同的内容.

    RLMResults <0x7fe5e3d22ec0>(
        [0]Data {
            time = 2016-01-08 05:51:12 +0000;
            title = test;
        }
    )

    生成如上的数据结构,只需创建类如下:

    // .h
    #import <Realm/Realm.h>
    
    @interface Data : RLMObject
    @property (nonatomic , strong) NSDate *time;
    @property (nonatomic , copy) NSString *title;
    
    @end
    
    // .m
    #import "Data.h"
    
    @implementation Data
    
    @end

    生成主键(Primary Keys)

    重写 +primaryKey 可以设置模型的主键。声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。 一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。

    @interface Person : RLMObject
    @property NSInteger id;
    @property NSString *name;
    @end
    
    @implementation Person
    + (NSString *)primaryKey {
        return @"id";
    }
    @end

    忽略属性(Ignored Properties)

    重写 +ignoredProperties 可以防止 Realm 存储数据模型的某个属性。Realm 将不会干涉这些属性的常规操作,它们将由成员变量(ivar)提供支持,并且您能够轻易重写它们的 setter 和 getter。

    @interface Person : RLMObject
    @property NSInteger tmpID;
    @property (readonly) NSString *name; // 只读属性将被自动忽略
    @property NSString *firstName;
    @property NSString *lastName;
    @end
    
    @implementation Person
    + (NSArray *)ignoredProperties {
        return @[@"tmpID"];
    }
    - (NSString *)name {
        return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
    }
    @end

    属性默认值

    重写+defaultPropertyValues可以在每次对象创建之后为其提供默认值。

    @interface Book : RLMObject
    @property float price;
    @property NSString *title;
    @end
    
    @implementation Book
    + (NSDictionary *)defaultPropertyValues {
        return @{@"price" : @0, @"title": @""};
    }
    @end

    创建嵌套数据模型

    数据结构:Person具有name、birthdate、dogs,Dog具有name、owner< Person >。

    RLMResults <0x7fb431f2bd60> (
        [0] Person {
            name = crylown;
            birthdate = 2016-01-08 06:02:23 +0000;
            dogs = RLMArray <0x7fb431f2fcd0> (
                [0] Dog {
                    name = myDog;
                    owner = Person {
                        name = crylown;
                        birthdate = 2016-01-08 06:02:23 +0000;
                        dogs = <Maximum depth exceeded>;
                    };
                },
                [1] Dog {
                    name = yourDog;
                    owner = Person {
                        name = crylown;
                        birthdate = 2016-01-08 06:02:23 +0000;
                        dogs = <Maximum depth exceeded>;
                    };
                }
            );
        }
    )

    生成如上的数据结构,创建数据模型代码如下:

    // .h
    #import <Realm/Realm.h>
    
    @class Person;
    
    // 狗狗的数据模型
    @interface Dog : RLMObject
    @property NSString *name;
    @property Person   *owner;
    @end
    RLM_ARRAY_TYPE(Dog) // 定义RLMArray<Dog>
    
    // 狗狗主人的数据模型
    @interface Person : RLMObject
    @property NSString      *name;
    @property NSDate        *birthdate;
    
    // 通过RLMArray建立关系
    @property RLMArray<Dog> *dogs;
    
    @end
    RLM_ARRAY_TYPE(Person) // 定义RLMArray<Person>
    
    
    // .m
    @implementation Dog
    @end  // 暂无使用
    
    @implementation Person
    @end  // 暂无使用

    使用Realm数据模型

    创建对象

    一般属性

    Data *data = [[Data alloc] init];
    
    data.time = [NSDate dateWithTimeIntervalSinceNow:0];
    
    data.title = @"test";

    等价于

     //字典
    Data *data = [[Data alloc] initWithValue:@{@"time":[NSDate dateWithTimeIntervalSinceNow:0],@"title":@"test"}];

    等价于

     //数组
     Data *data = [[Data alloc] initWithValue:@[[NSDate dateWithTimeIntervalSinceNow:0],@"test"]];

    嵌套属性

    Person *me = [[Person alloc] init];
    
    Dog *myDog = [[Dog alloc] init];
    myDog.name = @"myDog";
    myDog.owner = me;
    
    Dog *yourDog = [[Dog alloc] init];
    yourDog.name = @"yourDog";
    yourDog.owner = me;
    
    me.name = @"crylown";
    me.birthdate = [NSDate dateWithTimeIntervalSinceNow:1];
    
    // 将dog添加到 <RLMArray>dogs属性中
    [me.dogs addObject:myDog];
    [me.dogs addObject:yourDog];

    等价于

    Dog *myDog = [[Dog alloc] init];
    myDog.name = @"myDog";
    
    Dog *yourDog = [[Dog alloc] init];
    yourDog.name = @"yourDog";
    
    Person *me = [[Person alloc] initWithValue:@[@"crylown",[NSDate dateWithTimeIntervalSinceNow:1],@[myDog,yourDog]]];
    
    yourDog.owner = me;
    myDog.owner = me;

    等价于

    // 多重嵌套
    // dog.owner无法在这里设置
    Person *me = [[Person alloc] initWithValue:@[@"crylown",[NSDate dateWithTimeIntervalSinceNow:1],@[@[@"myDog"],@[@"yourDog"]]]];

    使用Realm进行数据管理

    在数据管理的过程中,常用的方法有:

     RLMRealm *realm = [RLMRealm defaultRealm];
    
    // 开放RLMRealm事务
    [realm beginWriteTransaction];
    
    // 在开放开放/提交事务之间进行数据处理
    
    // 提交事务
    [realm commitWriteTransaction];

    等价于

    [realm transactionWithBlock:^{
    
     // 进行数据处理
    
    }];

    添加数据

     RLMRealm *realm = [RLMRealm defaultRealm];
    
    //    开放RLMRealm事务
    [realm beginWriteTransaction];
    
    //    添加到数据库 me为RLMObject
    [realm addObject:me];
    
    //    提交事务
    [realm commitWriteTransaction];

    查询数据

    数据库查询

    // 查询默认的 Realm 数据库
    RLMResults *dogs = [Dog allObjects]; // 从默认的 Realm 数据库中,检索所有狗狗

    如果有需要,也可以查询指定的数据库

    // 查询指定的 Realm 数据库
    RLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // 获得一个指定的 Realm 数据库
    RLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // 从该 Realm 数据库中,检索所有狗狗

    条件查询
    1.使用断言字符串查询:

    RLMResults *tanDogs = [Dog objectsWhere:@"color = '棕黄色' AND name BEGINSWITH '大'"];

    2.// 使用 NSPredicate 查询

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@",
                                                     @"棕黄色", @"大"];
    RLMResults *tanDogs = [Dog objectsWithPredicate:pred];

    3.链式查询

    如果我们想获得获得棕黄色狗狗的查询结果,并且在这个查询结果的基础上再获得名字以“大”开头的棕黄色狗狗。

    RLMResults *tanDogs = [Dog objectsWhere:@"color = '棕黄色'"];
    RLMResults *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH '大'"];

    修改数据

    内容直接更新

    // author为数据库内RLMObject
    [realm beginWriteTransaction];
    author.name = @"托马斯·品钦";
    [realm commitWriteTransaction];

    根据主键更新
    如果您的数据模型中设置了主键的话,那么您可以使用+[RLMObject createOrUpdateInRealm:withValue:]来更新对象,或者当对象不存在时插入新的对象。

    // 创建一个带有主键的“书籍”对象,作为事先存储的书籍
    Book *cheeseBook = [[Book alloc] init];
    cheeseBook.title = @"奶酪食谱";
    cheeseBook.price = @9000;
    cheeseBook.id = @1;
    
    // 通过 id = 1 更新该书籍
    [realm beginWriteTransaction];
    [Book createOrUpdateInRealm:realm withValue:cheeseBook];
    [realm commitWriteTransaction];

    键值编码
    RLMObject、RLMResult 以及 RLMArray 都遵守键值编码(Key-Value Coding)(KVC)机制。

    RLMResults *persons = [Person allObjects];
    
    [[RLMRealm defaultRealm] transactionWithBlock:^{
      [[persons firstObject] setValue:@YES forKeyPath:@"isFirst"];
      // 将每个人的 planet 属性设置为“地球”
      [persons setValue:@"地球" forKeyPath:@"planet"];
    }];

    删除数据

    删除某个在Realm数据库中的数据。

    Book *cheeseBook = ... // 存储在 Realm 中的 Book 对象
    
    // 在事务中删除一个对象
    [realm beginWriteTransaction];
    [realm deleteObject:cheeseBook];
    [realm commitWriteTransaction];

    删除数据库中的所有数据。

    // 从 Realm 中删除所有数据
    [realm beginWriteTransaction];
    [realm deleteAllObjects];
    [realm commitWriteTransaction];

    数据排序

    RLMResults 允许您指定一个排序标准,从而可以根据一个或多个属性进行排序。比如说,下列代码将上面例子中返回的狗狗根据名字升序进行排序:

    // 排序名字以“大”开头的棕黄色狗狗
    RLMResults *sortedDogs = [[Dog objectsWhere:@"color = '棕黄色' AND name BEGINSWITH '大'"]
                             sortedResultsUsingProperty:@"name" ascending:YES];

    数据库配置

    一般地,我们使用的为默认的Realm数据库,即调用[RLMRealm defaultRealm]来初始化以及访问我们的realm变量。这个方法将会返回一个 RLMRealm对象,并指向您应用的 Documents (iOS) 或者 Application Support (OS X)文件夹下的一个名为“default.realm”的文件。

    许多 Realm API 中的方法都支持两种默认的数据库访问方式,一种是RLMRealm实例,另一种是访问默认 Realm 数据库的便捷版本。例如 [RLMObject allObjects] 等同于 [RLMObject allObjectsInRealm:[RLMRealm defaultRealm]]。

    Realm配置

    通过RLMRealmConfiguration您可以配置诸如 Realm 文件在何处存储之类的信息。
    配置同时也可以在每次您需要使用 Realm 实例的时候传递给[RLMRealm realmWithConfiguration:config error:&err],或者您也可以通过 [RLMRealmConfiguration setDefaultConfiguration:config] 来为默认的 Realm 数据库进行配置。
    比如说,假设有这样一个应用,用户必须登录到您的网站后台才能够使用,然后您希望这个应用支持快速帐号切换功能。 您可以为每个帐号创建一个特有的 Realm 文件,通过对默认配置进行更改,就可以直接使用默认的 Realm 数据库来直接访问了,如下所示:

    + (void)setDefaultRealmForUser:(NSString *)username {
      RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    
      // 使用默认的目录,但是使用用户名来替换默认的文件名
      config.path = [[[config.path stringByDeletingLastPathComponent]
                       stringByAppendingPathComponent:username]
                       stringByAppendingPathExtension:@"realm"];
    
      // 将这个配置应用到默认的 Realm 数据库当中
      [RLMRealmConfiguration setDefaultConfiguration:config];
    }

    其他的Realm数据库

    有的时候,在不同位置存储多个 Realm 数据库是十分有用的。 例如,如果您需要将您应用的某些数据打包到一个 Realm 文件中,作为主要 Realm 数据库的扩展。 您可以像以下代码这样做:

    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    
    // 获取需要打包文件的路径
    config.path = [[NSBundle mainBundle] pathForResource:@"MyBundledData" ofType:@"realm"];
    // 以只读模式打开文件,因为应用数据包并不可写
    config.readOnly = YES;
    
    // 通过配置打开 Realm 数据库
    RLMRealm *realm = [RLMRealm realmWithConfiguration:config];
    
    // 从打包的 Realm 数据库中读取某些数据
    RLMResults<Dog *> *dogs = [Dog objectsInRealm:realm where:@"age > 5"];

    请注意,使用自定义路径来初始化 Realm 数据库需要拥有路径所在位置的写入权限。 通常存储可写 Realm 文件的地方是位于 iOS 上的“Documents”文件夹以及位于 OS X 上的“Application Support”文件夹。 具体情况,请遵循苹果的 iOS 数据存储指南, 它推荐将文件存储在<Application_Home>/Library/Caches目录下

    错误处理

    在数据的处理中可能会出现失败的情况,在查看错误的时候,有相关方法可以使用:
    提交事务失败

    [realm commitWriteTransaction:(NSError * _Nullable __autoreleasing * _Nullable)]

    也可以使用

    [realm transactionWithBlock:^{
    
    } error:(NSError * _Nullable __autoreleasing * _Nullable)]

    配置数据库失败

    RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];

    要处理在指定线程中初次 Realm 数据库导致的错误, 给 error 参数提供一个 NSError 指针。

    数据迁移

    当您使用任意一个数据库时,您随时都可能打算修改您的数据模型。通过设置 RLMRealmConfiguration.schemaVersion 以及RLMRealmConfiguration.migrationBlock 可以定义一个迁移操作以及与之关联的架构版本。 迁移闭包将会提供提供相应的逻辑操作,以让数据模型从之前的架构转换到新的架构中来。 每当通过配置创建完一个 RLMRealm 之后,迁移闭包将会在迁移需要的时候,将给定的架构版本应用到更新 RLMRealm 操作中。
    如下所示是最简单的数据迁移的必需流程:

    // 在 [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];
  • 相关阅读:
    String、StringBuffer、StringBuilder
    动态规划引入—矩阵乘法
    flask中间件
    有状态服务,无状态服务
    python 工厂模式
    python 单例模式
    python 工厂模式
    python timedelta() 和relativedelta()的区别
    mongo 查看(集合)表结构
    logstash 实现数据源分流
  • 原文地址:https://www.cnblogs.com/tangyuanby2/p/7145997.html
Copyright © 2011-2022 走看看