一、Realm 框架
官網(wǎng)地址
介紹:
(1)、realm 是一個(gè)跨庫(kù)平臺(tái)的移動(dòng)端數(shù)據(jù)庫(kù)引擎,支持 iOS、OS X (objective-C和swift) 以及android
(2)、核心數(shù)據(jù)庫(kù)引擎C++ 打造,并不是建立在sqlite上的ORM,是擁有獨(dú)立的數(shù)據(jù)庫(kù)引擎.
(3)、性能,據(jù)說比sqlite 和coredata要快
(4)、易用性,相比sqlite、coredata,使用起來(lái)更加簡(jiǎn)單,更易入門.
二、使用教程
三、輔助工具
-
1、Realm Browser --> 可是化的訪問Realm 數(shù)據(jù)庫(kù)的工具,直接在 app store 搜索realm 即可下載.
Snip20180811_1.png
- 2、Xcode 插件 下載后直接運(yùn)行即可,成功后打開Xcode 可看見如下圖標(biāo),即成功了.
Snip20180811_2.png
四、Xcode導(dǎo)入realm 框架
- 創(chuàng)建podfile 安裝realm
platform :ios, '9.0'
target 'realm Demo' do
use_frameworks!
pod 'Realm', '~> 3.1.1'
end
五、Realm 實(shí)戰(zhàn)
一、簡(jiǎn)單的數(shù)據(jù)操作
- 1、準(zhǔn)備:
(1) 、創(chuàng)建的數(shù)據(jù)模型(objective-c 類)必須是繼承自RLMObject的對(duì)象.
(2)、由于realm 在自己的引擎內(nèi)部有很好的語(yǔ)義解釋系統(tǒng),所以objective-c 的許多屬性特性將被忽略,如: nonatomic, atomic, strong,copy,和weak等.因此為了避免誤解,官方推薦在編寫數(shù)據(jù)模型時(shí)不要使用任何的屬性特性.
Snip20180811_4.png
(3)、所有的必須屬性(排除忽略的)在對(duì)象添加到realm前,都必須被賦值.
(4)、 創(chuàng)建對(duì)象的方式,可以通過普通方式創(chuàng)建, 也可以使用 RLMObject 中的方法快速創(chuàng)建initWithValue
(5) 注意:Dog *dog =[ [Dog alloc]initWithValue:@{@"name":@"xiaohuang",@"age":@(22)}];
在realm 中只能存儲(chǔ),BOOL, bool,int, NSInteger,long, long long ,float ,double,NSString,NSData,NSDate,NSNumber ,像NSArray NSDictionary 是不能存儲(chǔ)的.
- 2、 使用RLMObject 對(duì)象,保存指定的模型:
(1) 、方式1:
(2) 、方式二://1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; //2. 創(chuàng)建 數(shù)據(jù)模型對(duì)象 Dog *dog = [[Dog alloc]initWithValue:@{@"name":@"xiaoHuang", @"age":@(2)}]; //3. 開啟寫入事物 [realm beginWriteTransaction]; //4. 添加數(shù)據(jù)模型 [realm addObject:dog]; //5. 提交寫入事物 [realm commitWriteTransaction]; // 注意: 對(duì)realm 數(shù)據(jù)庫(kù)的增 刪 查 改 的操作都必須寫在realm 的事物中來(lái)執(zhí)行,否則報(bào)錯(cuò)
(3)、方式三//1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; //2. 創(chuàng)建 數(shù)據(jù)模型對(duì)象 Dog *dog = [[Dog alloc]initWithValue:@{@"name":@"xiaoHuang", @"age":@(2)}]; // 3. [realm transactionWithBlock:^{ //4. 添加數(shù)據(jù)模型 [realm addObject:dog]; }];
注意://1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; //2. bolck 事物 [realm transactionWithBlock:^{ //3. 添加數(shù)據(jù)模型 [Dog createInRealm:realm withValue:@{@"name":@"xiaoHuang", @"age":@(2)}]; }];
在realm 的事物中沒有回滾的概念,如果執(zhí)行時(shí)出錯(cuò),它內(nèi)部會(huì)自動(dòng)回滾,外面想要監(jiān)聽操作的異常,就使用下面這個(gè)方法,如果錯(cuò)處就會(huì)有 errorNSError *err = nil; [realm transactionWithBlock:^{ //3.增 刪 查 改 }error:&err]; if(err){ NSLog(@"realm 在 操作過程中出現(xiàn)了錯(cuò)誤: %@",err); }
-
3 使用RLMRealm 對(duì)象, 更新指定的模型
(1) 、方式1: 在事物中直接更新對(duì)象.
注意:
此種方式更新的對(duì)象必須是已經(jīng)和realm 關(guān)聯(lián)的對(duì)象,否則無(wú)效,如下:[realm transactionWithBlock:^{ //4.注意 在realm 的事物中要 更新的 模型數(shù)據(jù)必須是 和 realm 已經(jīng)建立關(guān)系的模型數(shù)據(jù) // 否則沒辦法執(zhí)行 dog.age = 20; }];(2) 、方式2: 更具主鍵去更新(必須要告訴主鍵)
[realm transactionWithBlock:^{ // 注意: 通過這種方式 來(lái)添加或者更新某個(gè)數(shù)據(jù), 模型的類必須實(shí)現(xiàn) +(NSString *)primaryKey; 方法 [realm addOrUpdateObject:dog]; }];(3) 、方式3:
[realm transactionWithBlock:^{ // 注意: 通過這種方式 來(lái)添加或者更新某個(gè)數(shù)據(jù), 模型的類必須實(shí)現(xiàn) +(NSString *)primaryKey; 方法 [Dog createOrUpdateInRealm:realm withValue:@{@"name":@"xiaohei",@"age":@(2)} ]; }]; -
4、 使用RLMRealm 對(duì)象 ,刪除數(shù)據(jù)
(1)方式1: 刪除指定對(duì)象[realm transactionWithBlock:^{ // 注意: 要?jiǎng)h除的對(duì)象必須是和real 相關(guān)聯(lián)的對(duì)象, 自定義的沒有和realm 關(guān)聯(lián)的對(duì)象是不能被刪除的 [realm deleteObject:dog]; }]; // 也就是說,如果你要?jiǎng)h除某個(gè)制定個(gè)的數(shù)據(jù)對(duì)象, //要先從realm 中把它查找出來(lái),讓后在刪除.(2)方式2: 刪除所有的對(duì)象(有坑)
// 注意: 這個(gè)方法有點(diǎn)猛, 他會(huì)刪除你所有表的所有的內(nèi)容, 因此要慎用 [realm transactionWithBlock:^{ [realm deleteAllObjects]; }]; // 如果只想刪除某一張表,或一類數(shù)據(jù),那么要分2步. // 第一步: 通過realm 查出某一張表的所有的對(duì)象 RLMResults *rsts = [Dog allObjects]; // 這是一個(gè)支持快速遍歷的集合 // 第二不: 刪除查詢出來(lái)的所有的數(shù)據(jù) [realm transactionWithBlock:^{ [realm deleteObjects:rsts]; }];
-
5、使用RLMRealm 對(duì)象查詢數(shù)據(jù)(有坑)
(1) 、注意事項(xiàng):
??(1.1) 所有的查詢(包括查詢和屬性訪問)在realm 中都是延遲加載的,只有當(dāng)屬性被訪問時(shí),才能夠讀取響應(yīng)的數(shù)據(jù)
??(1.2) 查詢結(jié)果并不是數(shù)據(jù)的拷貝:修改查詢結(jié)果(在寫入事物中)會(huì)直接修改硬盤刪的數(shù)據(jù).
??(1.3)一旦檢索執(zhí)行后,RLMResults 將隨時(shí)保持更新.RLMRealm *realm = [RLMRealm defaultRealm]; // 查詢所有的數(shù)據(jù) RLMResults *rsts = [Dog allObjects]; NSLog(@"前=========rstsCount:%ld, rsts : %@",rsts.count, rsts); // 查詢完成后再插入一條數(shù)據(jù) [realm transactionWithBlock:^{ [realm addObject:[[Dog alloc]initWithValue:@{@"name":@"xiaoHei",@"age":@(2)}]]; }]; NSLog(@"后=========rstsCount:%ld, rsts : %@",rsts.count, rsts); // rsts 的數(shù)據(jù)信息會(huì)動(dòng)態(tài)的變化而不是固定的, 前后兩次打印信息是不同的(2)、查詢所有
// 所有繼承自 RLMObject 的對(duì)象都有這個(gè)方法 [Dog allObjects];(3)、條件查詢
// 查詢條件和 sql 語(yǔ)法一樣 RLMResults<Dog *> dogs = [Dog objectsWhere:@"age < 3"];(4)、排序
[dogs sortedResultsUsingProperty:@"age" ascending:YES];(5)、鏈?zhǔn)讲樵?
含義:
在查詢結(jié)果的基礎(chǔ)上,進(jìn)行二次查詢[dogs objectsWhere:@"address begingswith '成都' "];(6)分頁(yè)查詢 (沒有具體的分頁(yè),需要自己查出結(jié)果集,自己取想要的)
二、 Realm 支持的數(shù)據(jù)類型
- 1 、Realm 只支持 BOOL ,bool, NSinteger,long, long long,float,double,NSString, NSDate,NSDate,NSNumber 這幾種.
- 2 、注意: 不支持集合(NSArray,NSDictionary)類型, 但是可以支持RLMArray 這種集合類型
// RLMArray 是這樣定義的 @interface RLMArray<RLMObjectType> : NSObject<RLMCollection, NSFastEnumeration> // 可以看出, RLMArray 內(nèi)存儲(chǔ)的對(duì)象必須是繼承自 RLMObject 的對(duì)象, RLMArray 相當(dāng)于Foundation 框架中的NSArray //在Person 數(shù)據(jù)模型中使用集合 //第一步: 定義Dog 數(shù)據(jù)類型 @interface Dog : RLMObject @property NSString *name; @property(nonatomic, assign)int age; @end //這一行比不可少 RLM_ARRAY_TYPE(Dog) //第二步: 定義Person 數(shù)據(jù)類型 @interface Person : RLMObject @property NSString *name; @property int age; //1. 通過以下這種方式在模型數(shù)據(jù)中 定義 realm集合 //2. 指定集合中存儲(chǔ)的是 Dog 類型 @property RLMArray<Dog *><Dog> *dogs; @end
三 、realm 數(shù)據(jù)之間的關(guān)系
- 1 、對(duì)一關(guān)系:
當(dāng)一個(gè)對(duì)象持有另一個(gè)對(duì)象是,這種關(guān)系我們就稱之為對(duì)一關(guān)系,比如: 一個(gè)person 對(duì)象持有一個(gè)Dog 對(duì)象.//Person.h 文件 #import <Realm/Realm.h> #import "Dog.h" @interface Person : RLMObject @property NSInteger num; @property NSString *name; @property int age; /** realm 中的一對(duì)一的關(guān)系 */ @property Dog *dog; @end RLM_ARRAY_TYPE(Person) // Person.m 文件 #import "Person.h" @implementation Person +(NSString *)primaryKey{ return @"num"; } @end //Dog.h 文件 #import <Realm/Realm.h> @interface Dog : RLMObject @property NSInteger num; @property NSString *name; @property int age; @end RLM_ARRAY_TYPE(Dog) // Dog.m 文件 #import "Dog.h" @implementation Dog +(NSString *)primaryKey{ return @"num"; } @end // 實(shí)際方法應(yīng)用 - (void)testExample { //1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; Person *pson = [[Person alloc] initWithValue:@{@"num":@(1), @"name":@"zhangsan",@"age":@(18)}]; Dog *dog = [[Dog alloc]initWithValue:@{@"num":@(1), @"name":@"xiaoHei",@"age":@(1)}]; pson.dog = dog; // 3. [realm transactionWithBlock:^{ //4. 添加數(shù)據(jù)模型 [realm addObject:pson]; }]; NSLog(@"pson: %@",pson); }

- 2、 對(duì)多關(guān)系:
(1)在Dog類中,遵循指定協(xié)議方法,RLM_ARRAY_TYPE(Dog),RLM_ARRAY_TYPE宏創(chuàng)建了一個(gè)協(xié)議,從而允許RLMArray<Dog* ><Dog> * dogs;這種語(yǔ)法的使用.
(2)在Person類中,定義屬性@property RLMArray<Dog* ><Dog>* dogs;
注意:
(2.1)、雖然可以個(gè)RLMArray屬性賦值為nil,但是這僅用于清空數(shù)組,而不是移除數(shù)組,這意味著你總是可以向一個(gè)RLMArray屬性中添加對(duì)象,即使其被值為了nil//Person.h 文件 #import <Realm/Realm.h> #import "Dog.h" @interface Person : RLMObject @property NSInteger num; @property NSString *name; @property int age; /** realm 中的一對(duì)多的關(guān)系 */ @property RLMArray<Dog *><Dog> *dogs; @end RLM_ARRAY_TYPE(Person) // Person.m 文件 #import "Person.h" @implementation Person +(NSString *)primaryKey{ return @"num"; } @end //Dog.h 文件 #import <Realm/Realm.h> @interface Dog : RLMObject @property NSInteger num; @property NSString *name; @property int age; @end RLM_ARRAY_TYPE(Dog) // Dog.m 文件 #import "Dog.h" @implementation Dog +(NSString *)primaryKey{ return @"num"; } @end // 實(shí)際方法應(yīng)用 - (void)testExample { //1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; Person *pson = [[Person alloc] initWithValue:@{@"num":@(1), @"name":@"zhangsan",@"age":@(18)}]; Dog *dog1 = [[Dog alloc]initWithValue:@{@"num":@(1), @"name":@"xiaoHei",@"age":@(1)}]; Dog *dog2 = [[Dog alloc]initWithValue:@{@"num":@(2), @"name":@"xiaoHuang",@"age":@(2)}]; // person 的dogs 屬性是一個(gè)RLMArray, 在使用時(shí)不不會(huì)要?jiǎng)?chuàng)建realm 內(nèi)部會(huì)自動(dòng)創(chuàng)建 // 只需要將 屬性 添加進(jìn)去即可 [pson.dogs addObject:dog1]; [pson.dogs addObject:dog2]; // 3. [realm transactionWithBlock:^{ //4. 添加數(shù)據(jù)模型 [realm addObject:pson]; }]; NSLog(@"pson: %@",pson); }

- 3 、反向關(guān)系:
比如: Person 擁有Dog,Dog 又有相應(yīng)的主人.//Person.h 文件 #import <Realm/Realm.h> #import "Dog.h" @interface Person : RLMObject @property NSInteger num; @property NSString *name; @property int age; /** realm 中的一對(duì)多的關(guān)系 */ @property Dog *dog; @end RLM_ARRAY_TYPE(Person) // Person.m 文件 #import "Person.h" @implementation Person +(NSString *)primaryKey{ return @"num"; } @end //Dog.h 文件 #import <Realm/Realm.h> @interface Dog : RLMObject @property NSInteger num; @property NSString *name; @property int age; //1. 在realm 中有個(gè)特性,凡是 readonly 的屬性,在生成數(shù)據(jù)庫(kù)表時(shí),該字段會(huì)自動(dòng)被忽略 //2. 在realm 中如果需要定義反向?qū)傩?就按下面這個(gè)格式定義一個(gè)屬性即可,名字自己取 //3. 不需要指定反向?qū)ο蟮念愋? 只需要在.h文件說明反向?qū)傩缘?名稱,如下: @property(readonly)RLMLinkingObjects *master; @end RLM_ARRAY_TYPE(Dog) // Dog.m 文件 #import "Dog.h" @implementation Dog #pragma mark- 反向映射關(guān)系描述 // 此方法用戶描述 反向?qū)傩?的映射關(guān)系 +(NSDictionary<NSString *, RLMPropertyDescriptor*> *)linkingObjectsProperties{ // 描述: name: 反向映射關(guān)系的屬性名 // value, RLMPropertyDescriptor 描述器, 用于說明反向?qū)傩允悄膫€(gè)類, 中的哪個(gè)屬性 return @{@"master":[RLMPropertyDescriptor descriptorWithClass:NSClassFromString(@"Person") propertyName:@"dog"]}; } #pragma mark- 主鍵 +(NSString *)primaryKey{ return @"num"; } @end - (void)testExample { //1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; Person *pson = [[Person alloc] initWithValue:@{@"num":@(1), @"name":@"zhangsan",@"age":@(18)}]; Dog *dog = [[Dog alloc]initWithValue:@{@"num":@(1), @"name":@"xiaoHei",@"age":@(1)}]; pson.dog = dog; // 3. [realm transactionWithBlock:^{ //4. 添加數(shù)據(jù)模型 [realm addObject:pson]; }]; NSLog(@"pson: %@",pson); }反向關(guān)系打印結(jié)果
四、可空屬性&默認(rèn)值&忽略屬性
- 1、默認(rèn)情況下,屬性值是可空的,如果強(qiáng)制要求某個(gè)屬性非空,可以使用下面的方法.
(1)、遵循協(xié)議方法,如下:+(NSArray *)requiredProperties{ return @[@"name1",@"name2"]; } // 如果遵守了些協(xié)議方法說明了字段不能為nil , //那么給對(duì)應(yīng)的屬性設(shè)置為nil 時(shí)后操作數(shù)據(jù)庫(kù)就會(huì)報(bào)警告.

-
2、默認(rèn)值 (遵守協(xié)議)
+(NSDictionary *)defaultPropertyValues{ return @{@"name":@"value"}; } -
3、忽略屬性(某些不想存入數(shù)據(jù)庫(kù)的字段)
(1)方式1 、遵守協(xié)議+(NSArray *)ignoredProperties{ @[@"name", @"age"]; }(2) 方式2 、也可使用只讀屬性,即
// 只讀屬性,在realm 中是被忽略的. // 建議使用這種方式,直觀 @property(readonly)NSString *address;
五、通知
1、realm 實(shí)例會(huì)在每次寫入事物提交后,給其他線程上的realm實(shí)例發(fā)送通知.
-
2、 realm 通知的具體用法(方式1)
@property (nonatomic, strong) RLMNotificationToken * token; // realm 的通知必須強(qiáng)引用,否則收不到通知 self.token = [realm addNotificationBlock:^(RLMNotification notification, RLMRealm *realm) { // 接收到通知后的執(zhí)行邏輯 }]; // 移除通知 [self.token stop];注意:
(1)創(chuàng)建通知的token 是需要強(qiáng)引用的,否則通知是不生效的.
(2)移除通知時(shí)要使用對(duì)應(yīng)的token 3、 realm 通知的具體用法(方式2)
六、realm 數(shù)據(jù)庫(kù)操作
- 1 realm 的數(shù)據(jù)庫(kù)是采用用戶機(jī)制來(lái)區(qū)分?jǐn)?shù)據(jù)的,不同的用戶使用不同的數(shù)據(jù)庫(kù),以達(dá)到數(shù)據(jù)分離的目的
// 封裝方法,更具用戶名指定realm數(shù)據(jù)庫(kù) -(void)setDefaultRealmForUsr:(NSString *)usrName{ RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; // 使用默認(rèn)的存儲(chǔ)目錄,但是使用用戶名來(lái)替換默認(rèn)的文件名 NSURL *configFileUrl = [config.fileURL URLByDeletingLastPathComponent]; configFileUrl = [configFileUrl URLByAppendingPathComponent:usrName]; configFileUrl = [configFileUrl URLByAppendingPathExtension:@"realm"]; // 將這個(gè)配置應(yīng)用到默認(rèn)的 realm 數(shù)據(jù)當(dāng)中去 [RLMRealmConfiguration setDefaultConfiguration:config]; } // 測(cè)試 - (void)testExample { // 設(shè)置默認(rèn)的數(shù)據(jù)庫(kù) [self setDefaultRealmForUsr:@"zhangsan"]; //1. 獲取realm 對(duì)象 (可以理解成為數(shù)據(jù)庫(kù)的句柄, 對(duì)數(shù)據(jù)庫(kù)的增刪查改都要用到它) RLMRealm *realm = [RLMRealm defaultRealm]; Person *pson = [[Person alloc]initWithValue:@{@"name":@"張三",@"age":@(14)}]; [realm transactionWithBlock:^{ [realm addObject:pson]; }]; }
七 數(shù)據(jù)庫(kù)文件刪除
- 注意:
需要?jiǎng)h除數(shù)據(jù)庫(kù)文件以及輔助文件-(void)deleteRealm{ NSFileManager *fileMgr = [NSFileManager defaultManager]; RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; NSArray<NSURL *> *fileUrls = @[config.fileURL, [config.fileURL URLByAppendingPathExtension:@"lock"], [config.fileURL URLByAppendingPathExtension:@"log_a"], [config.fileURL URLByAppendingPathExtension:@"log_b"], [config.fileURL URLByAppendingPathExtension:@"note"], ]; for (NSURL *url in fileUrls) { NSError *err = nil; [fileMgr removeItemAtURL:url error:&err]; if (err) { NSLog(@"刪除 文件:%@ 失敗",url); } } }
八、realm 數(shù)據(jù)遷移
數(shù)據(jù)遷移適用于修改了模型的情況下
- 1 數(shù)據(jù)結(jié)構(gòu)遷移
- 2 數(shù)據(jù)遷移
- 3 屬性重命名
- 4 多版本增量式遷移
七、realm使用總結(jié)說明:
(1)、realm 底層不是基于sqlite 數(shù)據(jù)庫(kù)實(shí)現(xiàn)的.
(2)、realm底層是采用C++來(lái)實(shí)現(xiàn)的.
(3)、凡是在realm 的寫事物中指定的刪 改 對(duì)象代碼必須是和realm中有映射關(guān)系的.



