美文网首页数据存储
iOS 第三方数据库处理框架Realm的使用

iOS 第三方数据库处理框架Realm的使用

作者: NicoalsNC | 来源:发表于2019-10-24 18:09 被阅读0次

    Realm是目前比较流行的数据库处理框架。由 Y Combinator 公司孵化的一款支持运行在手机、平板和可穿戴设备上的嵌入式数据库(旨在取代CoreData和Sqlite)。Realm并不是对Core Data的简单封装,相反地,Realm并不是基于Core Data,也不是基于SQLite所构建的。它拥有自己的数据库存储引擎,可以高效且快速地完成数据库的构建操作。

    1. 官方资料

    2.Realm优势

    • Easy to Use(简单易用):不像Core Data和SQLite那样有着冗余、繁杂的知识和代码
    • Cross-Platform(跨平台):一个数据库,两个平台(iOS和Android)可以无缝衔接
    • Fast(高效):相对Core Data和SQLite高效快速,且代码量少

    3.集成

    1. 下载 Realm 的最新发布版本,并解压;
    2. 前往 Xcode 工程的 “General” 设置选项卡中,从 ios/static/ 目录中将 Realm.framework 拖曳到 Xcode 工程的文件导航器内。请确保勾选了 Copy items if needed,然后单击 Finish 按钮;
    3. 在 Xcode 文件导航器中选中工程。然后选择应用目标,前往 Build Phases 选项卡。在 Link Binary with Libraries 部分中单击 + 按钮,然后添加 libc++.tbdlibz.tbd

    说明:
    (1)对于使用Swift的童鞋,请讲Swift/RLMSupport.swift文件拖到项目中(确保Copy items if needed选中)
    (2)推荐使用Cocoapods进行安装,在Podfile中添加 pod 'Realm' 即可
    (3)也可以自行到Github上面下载代码进行编译,此处不作过多的介绍

    4.工具

    Realm官方向开发者提供了一个用于查看喝编辑Realm数据的工具 Realm Browser。可以下载查看创建的数据库,也可以创建初始数据库。

    查看真机沙盒数据库:


    查看真机沙盒数据库

    5.构建数据库

    考虑不同用户是需要使用不同数据库的,所以在构建时使用用户相关的标识来构建

    + (RLMRealm *)openRealmDataBase:(NSString *)username {
        NSLog(@"===1%@====",[NSDate date]);
        RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    
       // 使用默认的目录,但是请将文件名替换为用户名
       config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]
                                   URLByAppendingPathComponent:username]
                                   URLByAppendingPathExtension:@"realm"];
        
        //在某些情况下,您可能想要限制某些类只能够存储在指定 Realm 数据库中。
        config.objectClasses = @[NSClassFromString(@"Person").class, NSClassFromString(@"Dog").class];
        
        //对 shouldCompactOnLaunch 属性进行配置,来决定首次打开该 Realm 文件时是否对其进行压缩
        //原理:压缩操作将会读取 Realm 文件的全部内容,然后在另一个地方重新写成一个新的文件,最后将原文件进行替换。耗时!
        config.shouldCompactOnLaunch = ^BOOL(NSUInteger totalBytes, NSUInteger usedBytes){
            // totalBytes 指的是硬盘上文件的大小(以字节为单位)(数据 + 可用空间)
            // usedBytes 指的是文件中数据所使用的字节数
    
            // 如果文件的大小超过 100 MB且已用空间低于 50%时,进行压缩
            NSUInteger oneHundredMB = 100 * 1024 * 1024;
            return (totalBytes > oneHundredMB) && (usedBytes / totalBytes) < 0.5;
        };
        NSLog(@"===2%@====",[NSDate date]);
        NSError *error = nil;
        RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
        NSLog(@"===2%@====",[NSDate date]);
        if (!realm) {
            // 错误处理
        }
        return realm;
    }
    

    打开本地数据库

    + (RLMRealm *)openLocRealmDataBase{
        RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    
       // 使用默认的目录,但是请将文件名替换为用户名
       config.fileURL =  [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"Realmname"ofType:@"realm"]];
        NSError *error = nil;
        RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
        if (!realm) {
            // 错误处理
        }
        return realm;
    }
    

    6.删除数据库

    画风突转。删除数据库需要在应用启动时、在打开 Realm 数据库之前完成,要么只在显式声明的自动释放池 中打开 Realm 数据库,然后在自动释放池后面进行删除

    + (void)deleteRealmDataBase{
        @autoreleasepool {
            NSFileManager *manager = [NSFileManager defaultManager];
            RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
            NSArray<NSURL *> *realmFileURLs = @[
                config.fileURL,
                [config.fileURL URLByAppendingPathExtension:@"lock"],
                [config.fileURL URLByAppendingPathExtension:@"note"],
                [config.fileURL URLByAppendingPathExtension:@"management"]
            ];
            for (NSURL *URL in realmFileURLs) {
                NSError *error = nil;
                [manager removeItemAtURL:URL error:&error];
                if (error) {
                    // 错误处理
                }
            }
        }
    }
    

    7.创建数据模型

    #import <Realm/Realm.h>
    #import "Dog.h"
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Person : RLMObject
    @property NSInteger id;
    @property NSString             *name;
    @property NSDate               *birthdate;
    @property RLMArray<Dog *><Dog> *dogs;
    @end
    RLM_ARRAY_TYPE(Person)
    
    NS_ASSUME_NONNULL_END
    #import "Person.h"
    
    @implementation Person
    //表示name不能置为nil
    + (NSArray *)requiredProperties {
        return @[@"name"];
    }
    //默认属性值
    + (NSDictionary *)defaultPropertyValues {
        return @{@"name":@"Nicolas"};
    }
    //主键 允许对象的查询和更新更加高效,并且会强制要求每个值保持唯一性
    //一旦将带有主键的对象添加到 Realm 数据库,那么该对象的主键将无法更改。
    + (NSString *)primaryKey {
        return @"id";
    }
    //要为某个属性建立索引
    //Realm 支持为字符串、整型、布尔值以及 NSDate 属性建立索引。
    + (NSArray *)indexedProperties {
        return @[@"name"];
    }
    //忽略的字段
    + (NSArray *)ignoredProperties {
        return @[@"dogs"];
    }
    @end
    
    

    dog类

    #import <Realm/Realm.h>
    
    NS_ASSUME_NONNULL_BEGIN
    @class Person;
    @interface Dog : RLMObject
    @property NSString *name;
    @property Person   *owner;
    @end
    RLM_ARRAY_TYPE(Dog) // 定义 RLMArray<Dog> 类型
    
    NS_ASSUME_NONNULL_END
    
    #import "Dog.h"
    
    @implementation Dog
    
    @end
    

    说明:
    (1)Realm支持以下的属性(property)种类:BOOL, bool, int, NSInteger, long, float, double, CGFloat, NSString, NSDate 和 NSData。
    (2)你可以使用 RLMArray<Object> 和 RLMObject 来模拟对一或对多的关系(Realm也支持RLMObject继承)
    (3)Realm忽略了Objective-C的property attributes(如nonatomic, atomic, strong, copy, weak 等等)。 所以,推荐在创建模型的时候不要使用任何的property attributes。但是,假如你设置了,这些attributes会一直生效直到RLMObject被写入realm数据库。
    (4)定义了 RLM_ARRAY_TYPE(Dog) 这个宏表示支持 RLMArray< Dog > 该属性

    8.增删改查

    1:增

    + (void)addDataToRealm:(id)model{
        @autoreleasepool {
            if (model) {
                RLMRealm *realm = [HandleRealmModel openDefaultRealmDataBase];
                if (!realm) {
                    return;
                }
                [realm beginWriteTransaction];
                [realm addObject:model];
                [realm commitWriteTransaction];
            }
        }
    }
    //updata对象必须含有 primary key 
    + (void)addOrUpdateToRealm:(id)model{
        @autoreleasepool {
            if (model) {
                RLMRealm *realm = [HandleRealmModel openDefaultRealmDataBase];
                if (!realm ) {
                    return;
                }
                [realm beginWriteTransaction];
                [realm addOrUpdateObject:model];
                [realm commitWriteTransaction];
            }
        }
    }
    
    Person *p = [[Person alloc]init];
        p.name = @"nicolas";
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.dateFormat = @"yyyy-MM-dd";
        NSDate *date =  [dateFormatter dateFromString:@"1992-02-21"];
        p.birthdate = date;
        p.id = 1;
        Dog *dog = [[Dog alloc]init];
        dog.name = @"Peter";
        dog.owner = p;
        
        p.dogs = @[dog];
        [HandleRealmModel addOrUpdateToRealm:p];
    

    2:查

    查询所有数据[Person allObjects];
    或指定数据库查询及条件

    + (RLMResults *)objectsInRealm:(NSString *)className withWhere:(NSString *)filter{
        @autoreleasepool {
            RLMRealm *realm = [HandleRealmModel openDefaultRealmDataBase];
            if (!realm) {
                return nil;
            }
            return [NSClassFromString(className) objectsInRealm:realm where:filter];
        }
    }
    
    NSString *filter = @"name = 'nicolas'";
     RLMResults *rr = [HandleRealmModel objectsInRealm:@"Person" withWhere:filter];
    

    3:删

    + (void)deleteData:(id)model{
       @autoreleasepool {
           if (model) {
               RLMRealm *realm = [HandleRealmModel openDefaultRealmDataBase];
               if (!realm) {
                   return;
               }
               [realm beginWriteTransaction];
               [realm deleteObject:model];
               [realm commitWriteTransaction];
           }
       }
    }
    

    4:改

     Person *pp = [rr firstObject];
        [[HandleRealmModel openDefaultRealmDataBase] beginWriteTransaction];
        pp.name = @"nicolas New";
        [[HandleRealmModel openDefaultRealmDataBase] commitWriteTransaction];
    

    9.版本迁移

    //v1.0
    @interface Person : RLMObject
    @property NSString *firstName;
    @property NSString *lastName;
    @property int age;
    @end
    // v2.0  将firstName和lastName字段合并为一个字段fullName
    @interface Person : RLMObject
    @property NSString *fullName; // new property
    @property int age;
    @end
    // v3.0 添加新的属性email
    @interface Person : RLMObject
    @property NSString *fullName;
    @property NSString *email;   // new property
    @property int age;
    @end
    

    迁移

    [RLMRealm setSchemaVersion:2.0 forRealmAtPath:[RLMRealm defaultRealmPath] 
                             withMigrationBlock:^(RLMMigration *migration, 
                                                  NSUInteger oldSchemaVersion) {
      [migration enumerateObjects:Person.className 
                            block:^(RLMObject *oldObject, RLMObject *newObject) {
        //处理v2.0的更新
        if (oldSchemaVersion < 2.0) {
          newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]];
        }
        //处理v3.0的更新
        if(oldSchemaVersion < 3.0) {
          newObject[@"email"] = @"";
        }
      }];
    }];
    

    10.通知

    每当一次写事务完成Realm实例都会向其他线程上的实例发出通知,可以通过注册一个block来响应通知:

    self.token = [[HandleRealmModel openDefaultRealmDataBase] addNotificationBlock:^(NSString *note, RLMRealm * realm) {
        [tableView reloadData];
    }];
    

    demo

    补充:打包时,为了绕开苹果审核,需要在应用目标的 “Build Phases” 中创建一条新的 “Run Script Phase”,然后将下面这段代码粘贴到脚本文本框内:

    bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework/strip-frameworks.sh"
    

    如下图:


    image.png

    相关文章

      网友评论

        本文标题:iOS 第三方数据库处理框架Realm的使用

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