Realm ios踩坑筆記

冀正國發表於2018-11-05
  • Realm,為移動裝置而生!替代 SQLite 和 Core Data。為你省下數週的時間和數千行的程式碼,幫你創造出更棒的使用者體驗。--Realm官網

###一.優勢

Realm 並不是基於 Core Data ,也不是基於 SQLite 所構建的。它擁有自己的資料庫儲存引擎,可以高效且快速地完成資料庫的構建操作。

Realm 比使用 SQLite 要快,比ORM要快很多。 簡單。通過標註和物件操作實現資料操作。 版本升級時,資料遷移成本很低。 與rxjava、retrofit等Library有很好的互動。


###二.安裝方式

  • cocoapods(推薦):
1.[安裝CocoaPods 0.39.0 或者更高版本]
2.執行 pod repo update,以確保 CocoaPods 能夠獲取到Realm 的最新版本
3.在您的Podfile中,新增pod 'Realm'到您的 app 目標中,新增pod 'Realm/Headers'到您的測試目標中;
4.在終端執行pod install;
5.採用 CocoaPods 生成的.xcworkspace來執行工程!
6.如果需要在 Swift 當中使用的話,將於 Swift/RLMSupport.swift 的這個檔案拖動到您 Xcode 專案的檔案導航器當中,檢查以確保 **Copy items if needed** 選項已被勾選。
複製程式碼
  • Static Framework(靜態庫):
1.下載Realm 的最新版本並解壓;
2.將 Realm.framework 從 ios/static/資料夾拖曳到您 Xcode 專案中的檔案導航器當中。確保 **Copy items if needed** 選中然後單擊 **Finish**;
3.在 Xcode 檔案導航器中選擇您的專案,然後選擇您的應用目標,進入到** Build Phases** 選項卡中。在 **Link Binary with Libraries** 中單擊 + 號然後新增 **libc++.tbd** 以及 **libz.tbd**;
4.如果你在用 Swift 來使用 Realm,那麼將位於 Swift/RLMSupport.swift
的檔案拖曳進您 Xcode 專案中的檔案導航器當中,確保 **Copy items if needed** 選中。
複製程式碼

###三.Realm瀏覽器/資料庫管理器

在mac的Appstore下載一款名為Realm Browser的軟體即可進行管理

###四.Xcode外掛

  • 快速建立RLMObject物件

點選下載release zip ,解壓以後開啟plugin/RealmPlugin.xcodeproj進行編譯,重啟Xcode,command + N,拉倒底部,出現一個Realm Model Object的圖示,點選即可建立RLMObject物件

###五.API 參考

所有的類和方法什麼的都可以去API文件查閱

###六.建立資料模型

  • 建立一個資料模型,並建立引數
#import <Realm/Realm.h>
#import "ExpandCell_M.h"

typedef enum : NSUInteger {
TransactionDetailButtonTypeAll = 0,
TransactionDetailButtonTypeRecharge,
TransactionDetailButtonTypeDeposit,
TransactionDetailButtonTypeEarnings,
} TransactionDetailButtonType;

@interface ExpandSection_M : RLMObject
/// 是否隱藏
@property (nonatomic,assign) BOOL isExpand;

/// 時間標題
@property (nonatomic, copy) NSString *month;

///判斷型別(TransactionDetailButtonType型別轉化為NSInteger型別)
@property (nonatomic, assign) NSInteger DetailType;

///編碼
@property (nonatomic, assign) NSInteger SectionID;

@end
複製程式碼

####注意事項:

1.Realm支援以下的屬性property種類: BOOL,bool, int, NSInteger, long, float, double, CGFloat, NSString, NSDate 和NSData。 tip: 列舉及結構體無法進行儲存,需要進行資料型別轉換 2.你可以使用RLMArray 和RLMObject來模擬對一或對多的關係 3.Realm也支援RLMObject繼承。 4.屬性property特性:請注意Realm忽略了objective-c的property attributes,像nonatomic, atomic, strong, copy, weak等等。

所以,為了避免誤解,我們推薦你在寫入模型的時候不要使用任何的property attributes。但是,假如你設定了,這些attributes會一直生效直到RLMObject被寫入realm資料庫。 無論RLMObject在或不在realm中,你為getter和setter自定義的名字都能正常工作。

###七.資料模型定製

幾個存在的類方法進一步指定模型資訊:

+ (NSDictionary *)defaultPropertyValues; 可以被重寫,用以為新建的物件提供預設值。

+ (NSString *)primaryKey; 可以被重寫來設定模型的主鍵。定義主鍵可以提高效率並且確保唯一性。

+ (NSArray *)ignoredProperties; 可以被重寫來防止Realm儲存模型屬性。

###八.模型巢狀

// .h (官網示例)
#import <Realm/Realm.h>

@class Person;

// 狗狗的資料模型
@interface Dog : RLMObject
@property NSString *name;
@property Person *owner;
@end
RLM_ARRAY_TYPE(Dog) // 定義RLMArray<Dog>

// 狗狗主人的資料模型
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthdate;

// 通過RLMArray建立關係
@property RLMArray<Dog> *dogs;

@end
RLM_ARRAY_TYPE(Person) // 定義RLMArray<Person>


// .m
@implementation Dog
@end // 暫無使用

@implementation Person
@end // 暫無使用
複製程式碼

###八.使用Realm進行資料管理

  • 方法一:
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
// 進行資料處理
}];
複製程式碼
  • 方法二:
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
// 進行資料處理
[realm commitWriteTransaction];
複製程式碼

###九.查詢

####1.所有的資料抓取都很簡單,並且直到獲得資料之後才建立副本。

#####關於使用RLMResults的小貼士:

  • Realm的物件查詢返回一個RLMResults物件。它包含了一系列的RLMObject。(儲存什麼型別,取出就是什麼型別)

  • RLMResults有一個與NSArray很相似的interface(介面)並且物件可以通過索引(index)下標獲取。 但不同於NSArray的是,RLMResult是歸類的——它只能容納一種RLMObjects型別。(陣列型別單一)

  • 根據種類獲取物件從realm中獲取物件的最基本方法就是 [RLMObject allObjects], 它返回一個RLMResults,裡面是查詢的子類的所有RLMObject例項。

// 預設查詢 
RealmRLMResults *dogs = [Dog allObjects]; // 從預設Realm中查詢所有的?

// 指定查詢
RealmRLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // 得到一個指定的realm
RealmRLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // 在指定的realm中查詢所有的狗
複製程式碼

####2.謂詞/條件查詢

如果你對NSPredicate很熟悉的話, 那麼你就已經知道怎麼在realm裡面查詢了。 RLMObjects, RLMRealm, RLMArray和RLMResults都提供很好的methods來查詢特定的RLMObjects: 你只需要傳遞相應地NSPredicate例項,謂詞字串,謂詞格式字串,就可以獲取你想要的RLMObjects例項。就和NSObject一樣的。

舉個例子,下面的程式碼就是對上面的擴充。 通過呼叫[RLMObject objectsWhere:],獲得了預設realm資料庫中的所有顏色是黃褐色的,名字開頭是“B”的狗的例項。

// 條件查詢
RLMResults *tanDogs = [Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];
// 使用一個NSPredicate物件查詢
NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@", @"tan", @"B"];
tanDogs = [Dog objectsWithPredicate:pred];
複製程式碼

可以參看Apple的Predicates Programming Guide瞭解更多關於如何建立謂詞。

1.Realm支援很多常見的謂詞:在比較中, 運算元可以是屬性名或者常量。但是其中至少有一個是屬性名。 2.只有int, long, float, double, and NSDate這些屬性型別(property types)支援 ==, <=, <, >=, >, !=, 和 BETWEEN這些比較操作符。布林屬性可以支援==和!=。 3.在NSString和NSData屬性中, 我們支援的操作符有 ==, !=, BEGINSWITH, CONTAINS和ENDSWITH。 4.realm還支援如下的複合型操作符: AND, OR, NOT注意,我們雖然不支援aggregate expression type,但是我們支援BETWEEN操作符, 例如:

RLMResults *results = [Person objectsWhere:@"age BETWEEN %@", @[42, 43]];
複製程式碼

####3.條件排序

1.在很多情況下,我們都希望獲取或者查詢返回的結果都能按照一定條件排序。 所以,RLMArray支援使用指定的屬性對資料列進行排序。 2.Realm允許你指定一個排序要求並且根據一個或多個屬性進行排序。 3.舉例來說, 下面程式碼呼叫了[RLMObject objectsWhere:where:]對返回的資料”dogs”進行排序,排序的條件是名字的字母表升序。:

// Sort tan dogs with names starting with "B" by name
RLMResults *sortedDogs = [[Dog objectsWhere:
@"color = 'tan' AND name BEGINSWITH 'B'"] sortedResultsUsingProperty:@"name" ascending:YES];
複製程式碼

####4.鏈式查詢

  • Realm查詢引擎的一個獨特屬性就是它能夠進行簡單快捷的鏈式查詢, 而不需要像傳統資料庫一樣的麻煩。舉個例子來說,假如你要所有黃褐色的小狗的結果序列,然後從中查詢名字開頭是“B“的小狗。 你可以傳送如下的請求。
RLMResults *tanDogs = [Dog objectsWhere:@"color = 'tan'"];
RLMResults *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH 'B'"];
複製程式碼

####5.刪除資料

  • 刪除某個在Realm資料庫中的資料。
Book *cheeseBook = ... // 儲存在 Realm 中的 Book 物件
// 在事務中刪除一個物件
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];
複製程式碼
  • 刪除資料庫中的所有資料。
// 從 Realm 中刪除所有資料
[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];
複製程式碼

###十.通知

每當一次寫事務完成Realm例項都會向其他執行緒上的例項發出通知,可以通過註冊一個block來響應通知:

// Observe Realm Notifications
self.token = [realm addNotificationBlock:^(NSString *note, RLMRealm * realm) {
[myViewController updateUI];
}];
複製程式碼

只要有任何的引用指向這個返回的notification token,它就會保持啟用狀態。 在這個註冊更新的類裡,你需要有一個強引用來鉗制這個token, 因為一旦notification token被釋放,通知也會自動解除註冊。

具體內容: [Realm addNotificationBlock:]和[Realm removeNotificationBlock:]

###十一.Realm配置

每個使用者有自己不同的資料庫,在App啟動以後根據使用者的uid來設定資料庫,可以通過對預設配置進行更改,然後通過訪問預設資料庫來實現不同使用者不同資料庫. 因為設定了模型插入資料庫以後如果發生屬性更改,需要進行版本遷移.可以使用app的版本作為資料庫的版本,當版本迭代發生以後,改了模型的屬性,通過更改App的版本號實現版本遷移.

// 版本遷移和配置資料庫基本資料
- (void)setRealmMigration:(NSString *)username{
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];

// BTLog(@"%@---",config.fileURL);
// 使用預設的目錄,但是使用使用者名稱來替換預設的檔名
config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]
URLByAppendingPathComponent:username ? username : @"defalut"]
URLByAppendingPathExtension:@"realm"];

// 將這個配置應用到預設的 Realm 資料庫當中
[RLMRealmConfiguration setDefaultConfiguration:config];

// 設定新的架構版本。這個版本號必須高於之前所用的版本號(如果您之前從未設定過架構版本,那麼這個版本號設定為 0)
NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
NSString *appVersion = [infoDic objectForKey:@"CFBundleShortVersionString"];
uint64_t schemaVersion = appVersion.floatValue;
config.schemaVersion = schemaVersion;
// 設定閉包,這個閉包將會在開啟低於上面所設定版本號的 Realm 資料庫的時候被自動呼叫
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
// 目前我們還未進行資料遷移,因此 oldSchemaVersion == 0
if (oldSchemaVersion < schemaVersion) {
// 什麼都不要做!Realm 會自行檢測新增和需要移除的屬性,然後自動更新硬碟上的資料庫架構
}
};
// 告訴 Realm 為預設的 Realm 資料庫使用這個新的配置物件
[RLMRealmConfiguration setDefaultConfiguration:config];

// 現在我們已經告訴了 Realm 如何處理架構的變化,開啟檔案之後將會自動執行遷移
[RLMRealm defaultRealm];

// realm檔案的位置 
BTLog(@"fileurl===%@",[RLMRealmConfiguration defaultConfiguration].fileURL);
}
複製程式碼

相關文章