Realm踩坑筆記

[TOC]

  • Realm,為移動(dòng)設(shè)備而生!替代 SQLite 和 Core Data。為你省下數(shù)周的時(shí)間和數(shù)千行的代碼,幫你創(chuàng)造出更棒的用戶體驗(yàn)。--Realm官網(wǎng)

一.優(yōu)勢

Realm 并不是基于 Core Data ,也不是基于 SQLite 所構(gòu)建的。它擁有自己的數(shù)據(jù)庫存儲(chǔ)引擎,可以高效且快速地完成數(shù)據(jù)庫的構(gòu)建操作。

Realm 比使用 SQLite 要快,比ORM要快很多。
簡單。通過標(biāo)注和對(duì)象操作實(shí)現(xiàn)數(shù)據(jù)操作。
版本升級(jí)時(shí),數(shù)據(jù)遷移成本很低。
與rxjava、retrofit等Library有很好的交互。


二.安裝方式

  • cocoapods(推薦):
1.[安裝CocoaPods 0.39.0 或者更高版本]
2.運(yùn)行 pod repo update,以確保 CocoaPods 能夠獲取到Realm 的最新版本
3.在您的Podfile中,添加pod 'Realm'到您的 app 目標(biāo)中,添加pod 'Realm/Headers'到您的測試目標(biāo)中;
4.在終端運(yùn)行pod install;
5.采用 CocoaPods 生成的.xcworkspace來運(yùn)行工程!
6.如果需要在 Swift 當(dāng)中使用的話,將于 Swift/RLMSupport.swift 的這個(gè)文件拖動(dòng)到您 Xcode 項(xiàng)目的文件導(dǎo)航器當(dāng)中,檢查以確保 **Copy items if needed** 選項(xiàng)已被勾選。
  • Static Framework(靜態(tài)庫):
1.下載Realm 的最新版本并解壓;
2.將 Realm.framework 從 ios/static/文件夾拖曳到您 Xcode 項(xiàng)目中的文件導(dǎo)航器當(dāng)中。確保 **Copy items if needed** 選中然后單擊 **Finish**;
3.在 Xcode 文件導(dǎo)航器中選擇您的項(xiàng)目,然后選擇您的應(yīng)用目標(biāo),進(jìn)入到** Build Phases** 選項(xiàng)卡中。在 **Link Binary with Libraries** 中單擊 + 號(hào)然后添加 **libc++.tbd** 以及 **libz.tbd**;
4.如果你在用 Swift 來使用 Realm,那么將位于 Swift/RLMSupport.swift
 的文件拖曳進(jìn)您 Xcode 項(xiàng)目中的文件導(dǎo)航器當(dāng)中,確保 **Copy items if needed** 選中。

三.Realm瀏覽器/數(shù)據(jù)庫管理器

在mac的Appstore下載一款名為Realm Browser的軟件即可進(jìn)行管理

四.Xcode插件

  • 快速創(chuàng)建RLMObject對(duì)象

點(diǎn)擊下載release zip ,解壓以后打開plugin/RealmPlugin.xcodeproj進(jìn)行編譯,重啟Xcode,command + N,拉倒底部,出現(xiàn)一個(gè)Realm Model Object的圖標(biāo),點(diǎn)擊即可創(chuàng)建RLMObject對(duì)象

五.API 參考

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

六.創(chuàng)建數(shù)據(jù)模型

  • 創(chuàng)建一個(gè)數(shù)據(jù)模型,并創(chuàng)建參數(shù)
#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;

/// 時(shí)間標(biāo)題
@property (nonatomic, copy) NSString *month;

///判斷類型(TransactionDetailButtonType類型轉(zhuǎn)化為NSInteger類型)
@property (nonatomic, assign) NSInteger DetailType;

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

@end

注意事項(xiàng):

1.Realm支持以下的屬性property種類: BOOL,bool, int, NSInteger, long, float, double, CGFloat, NSString, NSDate 和NSData。
tip: 枚舉及結(jié)構(gòu)體無法進(jìn)行存儲(chǔ),需要進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換
2.你可以使用RLMArray<NSObject> 和RLMObject來模擬對(duì)一或?qū)Χ嗟年P(guān)系
3.Realm也支持RLMObject繼承。
4.屬性property特性:請注意Realm忽略了objective-c的property attributes,像nonatomic, atomic, strong, copy, weak等等。

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

七.數(shù)據(jù)模型定制

幾個(gè)存在的類方法進(jìn)一步指定模型信息:

+ (NSDictionary *)defaultPropertyValues; 可以被重寫,用以為新建的對(duì)象提供默認(rèn)值。

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

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

八.模型嵌套

// .h (官網(wǎng)示例)
#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進(jìn)行數(shù)據(jù)管理

  • 方法一:
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
 // 進(jìn)行數(shù)據(jù)處理
}];
  • 方法二:
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
// 進(jìn)行數(shù)據(jù)處理
[realm commitWriteTransaction];

九.查詢

1.所有的數(shù)據(jù)抓取都很簡單,并且直到獲得數(shù)據(jù)之后才創(chuàng)建副本。

關(guān)于使用RLMResults的小貼士:
  • Realm的對(duì)象查詢返回一個(gè)RLMResults對(duì)象。它包含了一系列的RLMObject。(保存什么類型,取出就是什么類型)

  • RLMResults有一個(gè)與NSArray很相似的interface(接口)并且對(duì)象可以通過索引(index)下標(biāo)獲取。
    但不同于NSArray的是,RLMResult是歸類的——它只能容納一種RLMObjects類型。(數(shù)組類型單一)

  • 根據(jù)種類獲取對(duì)象從realm中獲取對(duì)象的最基本方法就是 [RLMObject allObjects], 它返回一個(gè)RLMResults,里面是查詢的子類的所有RLMObject實(shí)例。

// 默認(rèn)查詢 
RealmRLMResults *dogs = [Dog allObjects]; // 從默認(rèn)Realm中查找所有的??

// 指定查詢
RealmRLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // 得到一個(gè)指定的realm
RealmRLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // 在指定的realm中查詢所有的狗

2.謂詞/條件查詢

如果你對(duì)NSPredicate很熟悉的話, 那么你就已經(jīng)知道怎么在realm里面查詢了。
RLMObjects, RLMRealm, RLMArray和RLMResults都提供很好的methods來查詢特定的RLMObjects:
你只需要傳遞相應(yīng)地NSPredicate實(shí)例,謂詞字符串,謂詞格式字符串,就可以獲取你想要的RLMObjects實(shí)例。就和NSObject一樣的。

舉個(gè)例子,下面的代碼就是對(duì)上面的拓展。 通過調(diào)用[RLMObject objectsWhere:],獲得了默認(rèn)realm數(shù)據(jù)庫中的所有顏色是黃褐色的,名字開頭是“B”的狗的實(shí)例。

// 條件查詢
RLMResults *tanDogs = [Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];
// 使用一個(gè)NSPredicate對(duì)象查詢
NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@", @"tan", @"B"];
tanDogs = [Dog objectsWithPredicate:pred];

可以參看Apple的Predicates Programming Guide了解更多關(guān)于如何創(chuàng)建謂詞。

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

RLMResults *results = [Person objectsWhere:@"age BETWEEN %@", @[42, 43]];

3.條件排序

1.在很多情況下,我們都希望獲取或者查詢返回的結(jié)果都能按照一定條件排序。
所以,RLMArray支持使用指定的屬性對(duì)數(shù)據(jù)列進(jìn)行排序。
2.Realm允許你指定一個(gè)排序要求并且根據(jù)一個(gè)或多個(gè)屬性進(jìn)行排序。
3.舉例來說, 下面代碼呼叫了[RLMObject objectsWhere:where:]對(duì)返回的數(shù)據(jù)”dogs”進(jìn)行排序,排序的條件是名字的字母表升序。:

// 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.鏈?zhǔn)讲樵?/h4>
  • Realm查詢引擎的一個(gè)獨(dú)特屬性就是它能夠進(jìn)行簡單快捷的鏈?zhǔn)讲樵儯?而不需要像傳統(tǒng)數(shù)據(jù)庫一樣的麻煩。舉個(gè)例子來說,假如你要所有黃褐色的小狗的結(jié)果序列,然后從中查找名字開頭是“B“的小狗。 你可以發(fā)送如下的請求。
RLMResults *tanDogs = [Dog objectsWhere:@"color = 'tan'"];
RLMResults *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH 'B'"];

5.刪除數(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];

十.通知

每當(dāng)一次寫事務(wù)完成Realm實(shí)例都會(huì)向其他線程上的實(shí)例發(fā)出通知,可以通過注冊一個(gè)block來響應(yīng)通知:

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

只要有任何的引用指向這個(gè)返回的notification token,它就會(huì)保持激活狀態(tài)。
在這個(gè)注冊更新的類里,你需要有一個(gè)強(qiáng)引用來鉗制這個(gè)token, 因?yàn)橐坏﹏otification token被釋放,通知也會(huì)自動(dòng)解除注冊。

具體內(nèi)容:
[Realm addNotificationBlock:]和[Realm removeNotificationBlock:]

十一.Realm配置

每個(gè)用戶有自己不同的數(shù)據(jù)庫,在App啟動(dòng)以后根據(jù)用戶的uid來設(shè)置數(shù)據(jù)庫,可以通過對(duì)默認(rèn)配置進(jìn)行更改,然后通過訪問默認(rèn)數(shù)據(jù)庫來實(shí)現(xiàn)不同用戶不同數(shù)據(jù)庫.
因?yàn)樵O(shè)置了模型插入數(shù)據(jù)庫以后如果發(fā)生屬性更改,需要進(jìn)行版本遷移.可以使用app的版本作為數(shù)據(jù)庫的版本,當(dāng)版本迭代發(fā)生以后,改了模型的屬性,通過更改App的版本號(hào)實(shí)現(xiàn)版本遷移.

// 版本遷移和配置數(shù)據(jù)庫基本數(shù)據(jù)
- (void)setRealmMigration:(NSString *)username{
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    
    //    BTLog(@"%@---",config.fileURL);
    // 使用默認(rèn)的目錄,但是使用用戶名來替換默認(rèn)的文件名
    config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]
                       URLByAppendingPathComponent:username ? username : @"defalut"]
                      URLByAppendingPathExtension:@"realm"];
    
    // 將這個(gè)配置應(yīng)用到默認(rèn)的 Realm 數(shù)據(jù)庫當(dāng)中
    [RLMRealmConfiguration setDefaultConfiguration:config];
    
    // 設(shè)置新的架構(gòu)版本。這個(gè)版本號(hào)必須高于之前所用的版本號(hào)(如果您之前從未設(shè)置過架構(gòu)版本,那么這個(gè)版本號(hào)設(shè)置為 0)
    NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
    NSString *appVersion = [infoDic objectForKey:@"CFBundleShortVersionString"];
    uint64_t schemaVersion = appVersion.floatValue;
    config.schemaVersion = schemaVersion;
    // 設(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 < schemaVersion) {
            // 什么都不要做!Realm 會(huì)自行檢測新增和需要移除的屬性,然后自動(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];
    
 // realm文件的位置   
    BTLog(@"fileurl===%@",[RLMRealmConfiguration defaultConfiguration].fileURL);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,456評(píng)論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評(píng)論 0 287
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,608評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,802評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,048評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評(píng)論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,424評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,762評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容