二挪略、Realm框架介紹:
realm是一個跨平臺移動數(shù)據(jù)庫引擎,支持iOS滔岳、OS X(Objective-C和Swift)以及Android杠娱;
核心數(shù)據(jù)引擎C++打造,并不是建立在SQLite之上的ORM, 是擁有獨立的數(shù)據(jù)庫存儲引擎谱煤;
比sqlite, coredata效率更快摊求、簡單易用。
三刘离、Realm輔助工具:
1室叉、RealmBrowser:可視化訪問Realm數(shù)據(jù)庫(AppStore中可下載)
2睹栖、Xcode插件:reaml-cocoa可以快速創(chuàng)建Realm可存儲模型對象
(https://github.com/realm/realm-cocoa)
四、Realm支持的數(shù)據(jù)類型:
BOOL, bool, int, NSInteger, long, long long, float, double, NSString, NSDate, NSData, and NSNumber
注意:不支持集合類型
解決方案:序列化成NSData進行存儲 或 轉換成RLMArray<RLMObject>進行存儲(麻煩)
五茧痕、Realm數(shù)據(jù)庫:
1. 用戶機制:不同的用戶, 使用不同的數(shù)據(jù)庫
+ (void)setDefaultRealmForUser:(NSString *)username {
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 使用默認的目錄野来,但是使用用戶名來替換默認的文件名
config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:username] URLByAppendingPathExtension:@"realm"];
// 將這個配置應用到默認的 Realm 數(shù)據(jù)庫當中
[RLMRealmConfiguration setDefaultConfiguration:config];
}
2. 只讀方式打開數(shù)據(jù)庫:config.readOnly = YES;
3. 數(shù)據(jù)庫文件刪除:需要刪除數(shù)據(jù)庫文件以及輔助文件(官方要求)
NSFileManager *manager = [NSFileManager defaultManager];
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
NSArray<NSURL *> *realmFileURLs = @[config.fileURL,
[config.fileURL URLByAppendingPathExtension:@"lock"],
[config.fileURL URLByAppendingPathExtension:@"log_a"],
[config.fileURL URLByAppendingPathExtension:@"log_b"],
[config.fileURL URLByAppendingPathExtension:@"note"]
];
for (NSURL *URL in realmFileURLs){
NSError *error = nil;
[manager removeItemAtURL:URL error:&error];
if(error){//處理錯誤}
}
六踪旷、Realm增刪改查:首先創(chuàng)建數(shù)據(jù)模型, 必須繼承自RLMObject
6.1 創(chuàng)建對象的方式:1. 普通創(chuàng)建
2. 通過父類RLMObject中的方法快速創(chuàng)建:initWithValue(數(shù)組或字典)
請注意:跟屬性順序需保持一致曼氛;
所有的必需屬性都必須在對象添加到Realm前被賦值;
由于Realm在自己的引擎內(nèi)部有很好的語義解釋系統(tǒng)令野,
所以 Objective?C 的許多屬性特性將被忽略搪锣,
如nonatomic, atomic, strong, copy 和 weak 等,
因此為了避免誤解彩掐,官方推薦在編寫數(shù)據(jù)模型的時候不要使用任何的屬性特性构舟。
6.2 簡單的數(shù)據(jù)操作:
1. 保存指定模型:
獲取RLMRealm對象:RLMRealm *realm = [RLMRealm defaultRealm];
方式1:開啟寫入事務:[realm beginWriteTransaction];
添加模型對象:[realm addObject:stu];
提交寫入事務:[realm commitWriteTransaction];
方式2:[realm transactionWithBlock:^{
[realm addObject:stu];
}];
方式3:[Stu createInRealm:realm withValue:@{@"stu_id": @22, @"name": @"馬冬梅2", @"age": @666}];
2. 更新指定模型
方式1:在事務中直接更新對象
[realm beginWriteTransaction];
stu.name = @"土豆";
[realm commitWriteTransaction];
方式2:根據(jù)主鍵進行更新
1. 要求操作的模型, 必須實現(xiàn)方法
+ (NSString *)primaryKey 返回主鍵
2. 在事務中調(diào)用方法:[realm addOrUpdateObject:stu2];
方式3:根據(jù)主鍵進行更新
1. 要求操作的模型, 必須實現(xiàn)方法
+ (NSString *)primaryKey 返回主鍵
2. 在事務中調(diào)用方法:
[Stu createOrUpdateInRealm:realm withValue:@{@"stu_id": @22, @"name": @"馬冬梅2", @"age": @666}];
3. 使用RLMRealm對象, 在事務中刪除數(shù)據(jù)
方式1:刪除指定的對象,
注意: 必須是從realm數(shù)據(jù)庫中獲取的模型對象, 而不是自己創(chuàng)建的
RLMObject *obj = [realm objectWithClassName:@"Stu" forPrimaryKey:@2];
[realm deleteObject:obj];
方式2:刪除所有對象
[realm deleteAllObjects];
4. 使用RLMRealm對象, 查詢數(shù)據(jù)
注意事項:1. 所有的查詢(包括查詢和屬性訪問)在Realm中都是延遲加載的堵幽,
只有當屬性被訪問時狗超,才能夠讀取相應的數(shù)據(jù);
2. 查詢結果并不是數(shù)據(jù)的拷貝:
修改查詢結果(在寫入事務中)會直接修改硬盤上的數(shù)據(jù);
3. 一旦檢索執(zhí)行之后, RLMResults將隨時保持更新。
查詢所有:[Stu allObjects]
條件查詢:RLMResults<Stu *> *stus = [Stu objectsWhere:@"name = '馬冬梅'"];
排序查詢:[stus sortedResultsUsingProperty:@"name" ascending:YES];
鏈式查詢:在查詢結果的基礎上, 進行二次查詢
[stus objectsWhere:@"address beginswith '北京'"];
分頁查詢:查詢出來的結果對象是懶加載, 只有真正訪問時,
才會加載相應對象, 所以這里的分頁, 其實就是從所有集合中分頁獲取即可
RLMResults<Dog *> *dogs = [Dog allObjects];
for (NSInteger i = 0; i < 5; i++) {
Dog *dog = dogs[i];
// …
}
七朴下、Realm關系:
7.1 對一關系:當一個對象持有另外一個對象時, 比如人有一個寵物??
7.2 對多關系:1. 在Dog中, 遵循指定協(xié)議方法
RLM_ARRAY_TYPE(Dog):
RLM_ARRAY_TYPE 宏創(chuàng)建了一個協(xié)議努咐,從而允許 RLMArray<Dog> 語法的使用
2. 在Person中, 定義屬性:
@property (nonatomic, strong) RLMArray<Dog *><Dog> *dogs;
雖然可以給 RLMArray 屬性賦值為 nil,
但是這僅用于“清空”數(shù)組殴胧,而不是用以移除數(shù)組渗稍。
這意味著您總是可以向一個 RLMArray 屬性中添加對象,
即使其被置為了 nil团滥。
Person屬性意義解釋:RLMArray: 屬性類型竿屹。
<Object *>: 屬性的特別化(generic specialization),
這可以阻止在編譯時使用錯誤對象類型的數(shù)組灸姊。
<Object>: 此RLMArray遵守的協(xié)議拱燃,
可以讓 Realm 知曉如何在運行時確定數(shù)據(jù)模型的結構。
7.3 反向關系:人擁有狗, 狗又有相應的主人?
1. Dog中定義屬性:@property (readonly) RLMLinkingObjects *master;
2. 實現(xiàn)協(xié)議方法, 標明鏈接關系:
+ (NSDictionary<NSString *,RLMPropertyDescriptor *> *)linkingObjectsProperties {
return @{
@"master": [RLMPropertyDescriptor descriptorWithClass:NSClassFromString(@"Stu") propertyName:@"dogs"]
};
}
八力惯、可空屬性&默認值&忽略屬性:
默認情況下, 屬性值可空, 如果強制要求某個屬性非空, 可以使用如下方法
8.1 設置屬性不能為nil:+ (NSArray *)requiredProperties碗誉;
特點:如果再次賦值為nil, 則會拋出異常錯誤
8.2 設置屬性默認值:+ (NSDictionary *)defaultPropertyValues;
8.3 設置可忽略屬性:+ (NSArray *)ignoredProperties父晶;
開發(fā)經(jīng)驗:可以借助忽略屬性&只讀屬性打造計算屬性, 完成集合以及UIImage對象的存儲與獲取
九哮缺、Realm數(shù)據(jù)庫通知:
數(shù)據(jù)庫和結果集都可添加通知;Realm實例將會在每次寫入事務提交后甲喝,
給其他線程上的Realm實例發(fā)送通知尝苇;必須持有返回的token
9.1 獲取Realm通知:
self.token = [realm addNotificationBlock:^(NSString *notification, RLMRealm * realm) {
// 接收到更改通知, 需要做的事情
}];
9.2 移除通知:[self.token stop];
十、Realm數(shù)據(jù)庫遷移:
10.1 數(shù)據(jù)結構的遷移:
// 在 [AppDelegate didFinishLaunchingWithOptions:] 中進行配置
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// 設置新的架構版本。
// 這個版本號必須高于之前所用的版本號
//(如果您之前從未設置過架構版本茎匠,那么這個版本號設置為 0)
config.schemaVersion = 1;
// 設置閉包格仲,這個閉包將會在打開低于上面所設置版本號的 Realm 數(shù)據(jù)庫的時候被自動調(diào)用
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
// 目前我們還未進行數(shù)據(jù)遷移,因此 oldSchemaVersion == 0
if (oldSchemaVersion < 1) {
// 什么都不要做诵冒!
// Realm 會自行檢測新增和需要移除的屬性凯肋,然后自動更新硬盤上的數(shù)據(jù)庫架構
}
};
// 告訴 Realm 為默認的 Realm 數(shù)據(jù)庫使用這個新的配置對象
[RLMRealmConfiguration setDefaultConfiguration:config];
// 現(xiàn)在我們已經(jīng)告訴了 Realm 如何處理架構的變化,打開文件之后將會自動執(zhí)行遷移
[RLMRealm defaultRealm];
10.2 數(shù)據(jù)的遷移:
// enumerateObjects:block: 方法遍歷了存儲在 Realm 文件中的每一個“Person”對象
[migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
// 將名字進行合并汽馋,存放在 fullName 域中
newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
oldObject[@"firstName"],
oldObject[@"lastName"]];
}];
10.3 屬性重命名:
[migration renamePropertyForClass:Person.className oldName:@"yearsSinceBirth" newName:@"age"];
10.4 多版本增量式遷移:根據(jù)數(shù)據(jù)庫版本的不同侮东,修改成最新版本(注意不要丟失數(shù)據(jù))
// enumerateObjects:block: 遍歷了存儲在 Realm 文件中的每一個“Person”對象
[migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
// 只有當 Realm 數(shù)據(jù)庫的架構版本為 0 的時候,才添加 “fullName” 屬性
if (oldSchemaVersion < 1) {
newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
oldObject[@"firstName"],
oldObject[@"lastName"]];
}
// 只有當 Realm 數(shù)據(jù)庫的架構版本為 0 或者 1 的時候豹芯,才添加“email”屬性
if (oldSchemaVersion < 2) {
newObject[@"email"] = @"";
}
}];