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

Realm是目前比较流行的数据库处理框架。由 Y Combinator 公司孵化的一款支持运行在手机、平板和可穿戴设备上的嵌入式数据库(旨在取代CoreData和Sqlite)。Realm并不是对Core Data的简单封装,相反地,Realm并不是基于Core Data,也不是基于SQLite所构建的。它拥有自己的数据库存储引擎,可以高效且快速地完成数据库的构建操作。
1. 官方资料
  • (最新版)Realm Objective?C官方文档地址 https://realm.io/docs/objc/latest/
  • (中文版)Realm Objective?C官方文档地址(内容相对英文版不一定是最新的)https://realm.io/cn/docs/objc/latest/
  • Realm官方API查阅手册 https://realm.io/docs/objc/latest/api/
  • GitHub源码地址 https://github.com/realm/realm-cocoa
  • 也可以直接点击压缩包下载
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++.tbd 和 libz.tbd。
说明:
(1)对于使用Swift的童鞋,请讲Swift/RLMSupport.swift文件拖到项目中(确保Copy items if needed选中)
(2)推荐使用Cocoapods进行安装,在Podfile中添加 pod 'Realm' 即可
(3)也可以自行到Github上面下载代码进行编译,此处不作过多的介绍
4.工具
【iOS|iOS 第三方数据库处理框架Realm的使用】Realm官方向开发者提供了一个用于查看喝编辑Realm数据的工具 Realm Browser。可以下载查看创建的数据库,也可以创建初始数据库。
查看真机沙盒数据库:

iOS|iOS 第三方数据库处理框架Realm的使用
文章图片
查看真机沙盒数据库 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 *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 #import "Dog.h" NS_ASSUME_NONNULL_BEGIN@interface Person : RLMObject @property NSInteger id; @property NSString*name; @property NSDate*birthdate; @property RLMArray *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 NS_ASSUME_NONNULL_BEGIN @class Person; @interface Dog : RLMObject @property NSString *name; @property Person*owner; @end RLM_ARRAY_TYPE(Dog) // 定义 RLMArray 类型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 和 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"

如下图:

iOS|iOS 第三方数据库处理框架Realm的使用
文章图片
image.png

    推荐阅读