Realm
Realm-Object-c杭措,見:
https://realm.io/cn/docs/objc/latest/
Realm官網(wǎng):
https://realm.io
使用流程
- 導(dǎo)入頭文件#import < Realm/Realm.h >.
- 創(chuàng)建類,繼承于RLMObject.
- 在類中生成數(shù)據(jù)模型.
- 在需要的地方創(chuàng)建實(shí)例,使用Realm方法調(diào)用.
數(shù)據(jù)模型
創(chuàng)建簡(jiǎn)單數(shù)據(jù)模型
簡(jiǎn)單地,繼承RLMObject創(chuàng)建類,在.h中通過屬性定義不同的內(nèi)容.
RLMResults <0x7fe5e3d22ec0>(
[0]Data {
time = 2016-01-08 05:51:12 +0000;
title = test;
}
)
生成如上的數(shù)據(jù)結(jié)構(gòu),只需創(chuàng)建類如下:
// .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 可以設(shè)置模型的主鍵扩劝。聲明主鍵之后金赦,對(duì)象將被允許查詢聚假,更新速度更加高效碌廓,并且要求每個(gè)對(duì)象保持唯一性敬锐。 一旦帶有主鍵的對(duì)象被添加到 Realm 之后背传,該對(duì)象的主鍵將不可修改。
@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end
@implementation Person
+ (NSString *)primaryKey {
return @"id";
}
@end
忽略屬性(Ignored Properties)
重寫 +ignoredProperties 可以防止 Realm 存儲(chǔ)數(shù)據(jù)模型的某個(gè)屬性台夺。Realm 將不會(huì)干涉這些屬性的常規(guī)操作径玖,它們將由成員變量(ivar)提供支持,并且您能夠輕易重寫它們的 setter 和 getter颤介。
@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // 只讀屬性將被自動(dòng)忽略
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation Person
+ (NSArray *)ignoredProperties {
return @[@"tmpID"];
}
- (NSString *)name {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end
屬性默認(rèn)值
重寫+defaultPropertyValues可以在每次對(duì)象創(chuàng)建之后為其提供默認(rèn)值梳星。
@interface Book : RLMObject
@property float price;
@property NSString *title;
@end
@implementation Book
+ (NSDictionary *)defaultPropertyValues {
return @{@"price" : @0, @"title": @""};
}
@end
創(chuàng)建嵌套數(shù)據(jù)模型
數(shù)據(jù)結(jié)構(gòu):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>;
};
}
);
}
)
生成如上的數(shù)據(jù)結(jié)構(gòu),創(chuàng)建數(shù)據(jù)模型代碼如下:
// .h
#import <Realm/Realm.h>
@class Person;
// 狗狗的數(shù)據(jù)模型
@interface Dog : RLMObject
@property NSString *name;
@property Person *owner;
@end
RLM_ARRAY_TYPE(Dog) // 定義RLMArray<Dog>
// 狗狗主人的數(shù)據(jù)模型
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthdate;
// 通過RLMArray建立關(guān)系
@property RLMArray<Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // 定義RLMArray<Person>
// .m
@implementation Dog
@end // 暫無使用
@implementation Person
@end // 暫無使用
使用Realm數(shù)據(jù)模型
創(chuàng)建對(duì)象
一般屬性
Data *data = [[Data alloc] init];
data.time = [NSDate dateWithTimeIntervalSinceNow:0];
data.title = @"test";
等價(jià)于
//字典
Data *data = [[Data alloc] initWithValue:@{@"time":[NSDate dateWithTimeIntervalSinceNow:0],@"title":@"test"}];
等價(jià)于
//數(shù)組
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];
等價(jià)于
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;
等價(jià)于
// 多重嵌套
// dog.owner無法在這里設(shè)置
Person *me = [[Person alloc] initWithValue:@[@"crylown",[NSDate dateWithTimeIntervalSinceNow:1],@[@[@"myDog"],@[@"yourDog"]]]];
使用Realm進(jìn)行數(shù)據(jù)管理
在數(shù)據(jù)管理的過程中,常用的方法有:
RLMRealm *realm = [RLMRealm defaultRealm];
// 開放RLMRealm事務(wù)
[realm beginWriteTransaction];
// 在開放開放/提交事務(wù)之間進(jìn)行數(shù)據(jù)處理
// 提交事務(wù)
[realm commitWriteTransaction];
等價(jià)于
[realm transactionWithBlock:^{
// 進(jìn)行數(shù)據(jù)處理
}];
添加數(shù)據(jù)
RLMRealm *realm = [RLMRealm defaultRealm];
// 開放RLMRealm事務(wù)
[realm beginWriteTransaction];
// 添加到數(shù)據(jù)庫 me為RLMObject
[realm addObject:me];
// 提交事務(wù)
[realm commitWriteTransaction];
查詢數(shù)據(jù)
數(shù)據(jù)庫查詢
// 查詢默認(rèn)的 Realm 數(shù)據(jù)庫
RLMResults *dogs = [Dog allObjects]; // 從默認(rèn)的 Realm 數(shù)據(jù)庫中辕近,檢索所有狗狗
如果有需要,也可以查詢指定的數(shù)據(jù)庫
// 查詢指定的 Realm 數(shù)據(jù)庫
RLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // 獲得一個(gè)指定的 Realm 數(shù)據(jù)庫
RLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // 從該 Realm 數(shù)據(jù)庫中韵吨,檢索所有狗狗
條件查詢
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.鏈?zhǔn)讲樵?/p>
如果我們想獲得獲得棕黃色狗狗的查詢結(jié)果,并且在這個(gè)查詢結(jié)果的基礎(chǔ)上再獲得名字以“大”開頭的棕黃色狗狗移宅。
RLMResults *tanDogs = [Dog objectsWhere:@"color = '棕黃色'"];
RLMResults *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH '大'"];
修改數(shù)據(jù)
內(nèi)容直接更新
// author為數(shù)據(jù)庫內(nèi)RLMObject
[realm beginWriteTransaction];
author.name = @"托馬斯·品欽";
[realm commitWriteTransaction];
根據(jù)主鍵更新
如果您的數(shù)據(jù)模型中設(shè)置了主鍵的話归粉,那么您可以使用+[RLMObject createOrUpdateInRealm:withValue:]來更新對(duì)象,或者當(dāng)對(duì)象不存在時(shí)插入新的對(duì)象漏峰。
// 創(chuàng)建一個(gè)帶有主鍵的“書籍”對(duì)象糠悼,作為事先存儲(chǔ)的書籍
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)機(jī)制浅乔。
RLMResults *persons = [Person allObjects];
[[RLMRealm defaultRealm] transactionWithBlock:^{
[[persons firstObject] setValue:@YES forKeyPath:@"isFirst"];
// 將每個(gè)人的 planet 屬性設(shè)置為“地球”
[persons setValue:@"地球" forKeyPath:@"planet"];
}];
刪除數(shù)據(jù)
刪除某個(gè)在Realm數(shù)據(jù)庫中的數(shù)據(jù)绢掰。
Book *cheeseBook = ... // 存儲(chǔ)在 Realm 中的 Book 對(duì)象
// 在事務(wù)中刪除一個(gè)對(duì)象
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];
刪除數(shù)據(jù)庫中的所有數(shù)據(jù)。
// 從 Realm 中刪除所有數(shù)據(jù)
[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];
數(shù)據(jù)排序
RLMResults 允許您指定一個(gè)排序標(biāo)準(zhǔn)童擎,從而可以根據(jù)一個(gè)或多個(gè)屬性進(jìn)行排序滴劲。比如說,下列代碼將上面例子中返回的狗狗根據(jù)名字升序進(jìn)行排序:
// 排序名字以“大”開頭的棕黃色狗狗
RLMResults *sortedDogs = [[Dog objectsWhere:@"color = '棕黃色' AND name BEGINSWITH '大'"]
sortedResultsUsingProperty:@"name" ascending:YES];
數(shù)據(jù)庫配置
一般地,我們使用的為默認(rèn)的Realm數(shù)據(jù)庫,即調(diào)用[RLMRealm defaultRealm]來初始化以及訪問我們的realm變量顾复。這個(gè)方法將會(huì)返回一個(gè) RLMRealm對(duì)象班挖,并指向您應(yīng)用的 Documents (iOS) 或者 Application Support (OS X)文件夾下的一個(gè)名為“default.realm”的文件。
許多 Realm API 中的方法都支持兩種默認(rèn)的數(shù)據(jù)庫訪問方式芯砸,一種是RLMRealm實(shí)例萧芙,另一種是訪問默認(rèn) Realm 數(shù)據(jù)庫的便捷版本给梅。例如 [RLMObject allObjects] 等同于 [RLMObject allObjectsInRealm:[RLMRealm defaultRealm]]。
Realm配置
通過RLMRealmConfiguration您可以配置諸如 Realm 文件在何處存儲(chǔ)之類的信息双揪。
配置同時(shí)也可以在每次您需要使用 Realm 實(shí)例的時(shí)候傳遞給[RLMRealm realmWithConfiguration:config error:&err]动羽,或者您也可以通過 [RLMRealmConfiguration setDefaultConfiguration:config] 來為默認(rèn)的 Realm 數(shù)據(jù)庫進(jìn)行配置。
比如說渔期,假設(shè)有這樣一個(gè)應(yīng)用运吓,用戶必須登錄到您的網(wǎng)站后臺(tái)才能夠使用,然后您希望這個(gè)應(yīng)用支持快速帳號(hào)切換功能疯趟。 您可以為每個(gè)帳號(hào)創(chuàng)建一個(gè)特有的 Realm 文件拘哨,通過對(duì)默認(rèn)配置進(jìn)行更改,就可以直接使用默認(rèn)的 Realm 數(shù)據(jù)庫來直接訪問了信峻,如下所示:
+ (void)setDefaultRealmForUser:(NSString *)username {
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 使用默認(rèn)的目錄倦青,但是使用用戶名來替換默認(rèn)的文件名
config.path = [[[config.path stringByDeletingLastPathComponent]
stringByAppendingPathComponent:username]
stringByAppendingPathExtension:@"realm"];
// 將這個(gè)配置應(yīng)用到默認(rèn)的 Realm 數(shù)據(jù)庫當(dāng)中
[RLMRealmConfiguration setDefaultConfiguration:config];
}
其他的Realm數(shù)據(jù)庫
有的時(shí)候,在不同位置存儲(chǔ)多個(gè) Realm 數(shù)據(jù)庫是十分有用的盹舞。 例如产镐,如果您需要將您應(yīng)用的某些數(shù)據(jù)打包到一個(gè) Realm 文件中,作為主要 Realm 數(shù)據(jù)庫的擴(kuò)展踢步。 您可以像以下代碼這樣做:
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 獲取需要打包文件的路徑
config.path = [[NSBundle mainBundle] pathForResource:@"MyBundledData" ofType:@"realm"];
// 以只讀模式打開文件磷账,因?yàn)閼?yīng)用數(shù)據(jù)包并不可寫
config.readOnly = YES;
// 通過配置打開 Realm 數(shù)據(jù)庫
RLMRealm *realm = [RLMRealm realmWithConfiguration:config];
// 從打包的 Realm 數(shù)據(jù)庫中讀取某些數(shù)據(jù)
RLMResults<Dog *> *dogs = [Dog objectsInRealm:realm where:@"age > 5"];
請(qǐng)注意,使用自定義路徑來初始化 Realm 數(shù)據(jù)庫需要擁有路徑所在位置的寫入權(quán)限贾虽。 通常存儲(chǔ)可寫 Realm 文件的地方是位于 iOS 上的“Documents”文件夾以及位于 OS X 上的“Application Support”文件夾逃糟。 具體情況,請(qǐng)遵循蘋果的 iOS 數(shù)據(jù)存儲(chǔ)指南, 它推薦將文件存儲(chǔ)在<Application_Home>/Library/Caches目錄下
錯(cuò)誤處理
在數(shù)據(jù)的處理中可能會(huì)出現(xiàn)失敗的情況,在查看錯(cuò)誤的時(shí)候,有相關(guān)方法可以使用:
提交事務(wù)失敗
[realm commitWriteTransaction:(NSError * _Nullable __autoreleasing * _Nullable)]
也可以使用
[realm transactionWithBlock:^{
} error:(NSError * _Nullable __autoreleasing * _Nullable)]
配置數(shù)據(jù)庫失敗
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
要處理在指定線程中初次 Realm 數(shù)據(jù)庫導(dǎo)致的錯(cuò)誤蓬豁, 給 error 參數(shù)提供一個(gè) NSError 指針绰咽。
數(shù)據(jù)遷移
當(dāng)您使用任意一個(gè)數(shù)據(jù)庫時(shí),您隨時(shí)都可能打算修改您的數(shù)據(jù)模型地粪。通過設(shè)置 RLMRealmConfiguration.schemaVersion 以及RLMRealmConfiguration.migrationBlock 可以定義一個(gè)遷移操作以及與之關(guān)聯(lián)的架構(gòu)版本取募。 遷移閉包將會(huì)提供提供相應(yīng)的邏輯操作,以讓數(shù)據(jù)模型從之前的架構(gòu)轉(zhuǎn)換到新的架構(gòu)中來蟆技。 每當(dāng)通過配置創(chuàng)建完一個(gè) RLMRealm 之后玩敏,遷移閉包將會(huì)在遷移需要的時(shí)候,將給定的架構(gòu)版本應(yīng)用到更新 RLMRealm 操作中质礼。
如下所示是最簡(jiǎn)單的數(shù)據(jù)遷移的必需流程:
// 在 [AppDelegate didFinishLaunchingWithOptions:] 中進(jìn)行配置
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 設(shè)置新的架構(gòu)版本旺聚。這個(gè)版本號(hào)必須高于之前所用的版本號(hào)(如果您之前從未設(shè)置過架構(gòu)版本,那么這個(gè)版本號(hào)設(shè)置為 0)
config.schemaVersion = 1;
// 設(shè)置閉包眶蕉,這個(gè)閉包將會(huì)在打開低于上面所設(shè)置版本號(hào)的 Realm 數(shù)據(jù)庫的時(shí)候被自動(dòng)調(diào)用
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
// 目前我們還未進(jìn)行數(shù)據(jù)遷移砰粹,因此 oldSchemaVersion == 0
if (oldSchemaVersion < 1) {
// 什么都不要做!Realm 會(huì)自行檢測(cè)新增和需要移除的屬性造挽,然后自動(dòng)更新硬盤上的數(shù)據(jù)庫架構(gòu)
}
};
// 告訴 Realm 為默認(rèn)的 Realm 數(shù)據(jù)庫使用這個(gè)新的配置對(duì)象
[RLMRealmConfiguration setDefaultConfiguration:config];
// 現(xiàn)在我們已經(jīng)告訴了 Realm 如何處理架構(gòu)的變化碱璃,打開文件之后將會(huì)自動(dòng)執(zhí)行遷移
[RLMRealm defaultRealm];