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

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容