Realm的學(xué)習(xí)筆記—1

這篇直接搬了一份官方文檔過來看的 由于之前沒用markdown搞的亂七八糟的 所以重新做了一份 后面看到官網(wǎng)的中文文檔更新不及時(shí)看著英文翻譯了一點(diǎn) 搞的更亂了 :( 英文好的直接點(diǎn)右邊->官方OC文檔

Realm是一個(gè)移動(dòng)端的數(shù)據(jù)庫(kù)远剩,RealmSQLiteCoreData的替代者蛮原。它可以節(jié)省你成千上萬行代碼和數(shù)周的工作,并且讓你精巧的制作出令人驚嘆的用戶體驗(yàn)虾标。

文檔版本 0.93.2
github上獲取

需求:
iOS7以上 OS X10.9以上 WatchKit.
Xcode 6 及以上 必需.
支持Objective-C Swift 1.2 Swift 2.0

安裝

靜態(tài)庫(kù)安裝 (Objective-C & Swift)

1.下載最新的Realm發(fā)行版本并在本地解壓蔓腐。
2.從 ios/static/目錄里,把Realm.framework文件拖動(dòng)到你的Xcode開發(fā)項(xiàng)目里的File Navigator 中叮阅。 確保Copy items into destination group’s folder已經(jīng)被選中刁品,按Finish。
3.在Xcode file explorer中選中你要的開發(fā)項(xiàng)目. 選擇target,點(diǎn)擊Build Phases選項(xiàng). 在Link Binary with Libraries里按+,添加libc++.dylib浩姥。
4.如果使用Realm + Swift,拖動(dòng)Swift/RLMSupport.swift到你的Xcode projectFile Navigator中,點(diǎn)選Copy items if needed挑随。
5.如果在OSX項(xiàng)目中使用Realm,點(diǎn)擊左上角的 + 勒叠,選擇New Copy Files Phase兜挨,將其重命名為Copy Frameworks, 將Destination設(shè)置為Frameworks,并且添加Realm.framework眯分。

動(dòng)態(tài)庫(kù)安裝 (Objective-C & Swift)

1.下載最新的Realm發(fā)行版本并在本地解壓拌汇。
2.來到Xcode工程的General設(shè)置界面,從 ios/dynamic/或者osx/ 目錄里,把Realm.framework文件拖動(dòng)到Embedded Binaries里面。 確保Copy items into destination group’s folder已經(jīng)被選中弊决,按Finish噪舀。
3.In your unit test target’s “Build Settings”, add the parent path to Realm.framework in the “Framework Search Paths” section.
4.If using Realm with Swift, drag the file at Swift/RLMSupport.swift into the File Navigator of your Xcode project, checking the Copy items if needed checkbox.
5.If using Realm in an iOS 8 project, create a new “Run Script Phase” in your app’s target’s “Build Phases” and paste the following snippet in the script text field: bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework/strip-frameworks.sh" This step is required to work around an App Store submission bug when archiving universal binaries.

通過CocoaPods安裝 (Objective-C Only)

如果你使用CocoaPods…
1.把pod "Realm"添加到你的Podfile中。
2.在命令行中執(zhí)行pod install飘诗。
3.將CocoaPods生成的.xcworkspace運(yùn)用到你的開發(fā)項(xiàng)目中即可与倡。

Xcode 插件

我們的Xcode插件讓新建Realm模型model很輕松。安裝Realm Xcode插件的最簡(jiǎn)單的途徑就是通過AlcatrazRealmPlugin目錄下昆稿。
你也可以自行手動(dòng)安裝:打開release zip中的plugin/RealmPlugin.xcodeproj纺座, 點(diǎn)擊編譯build。 重啟Xcode生效溉潭。
如果你使用Xcode新建文件File > New > File… — or ? N,可以看到有一個(gè)新建Realm模型create a new realm model的選項(xiàng)净响。

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

我們另外提供了一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)管理工具,用來查看和編輯realm數(shù)據(jù)庫(kù).realm喳瓣。
你可以從browser/release zip目錄下找到它别惦。
使用菜單中的工具tool>生成演示數(shù)據(jù)庫(kù)generate demo database, 你可以生成一個(gè)測(cè)試數(shù)據(jù)庫(kù)(當(dāng)然里面的數(shù)據(jù)是樣本數(shù)據(jù)).

API 參考

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

示例

你可以在examples/路徑里面找到一個(gè)文件,叫做release zip夫椭。 里面包含了Objective-C, SwiftRubyMotion的示例程序掸掸。 它們演示了Realm得很多功能和特性,例如數(shù)據(jù)庫(kù)遷移,如何與UITableViewController’s一起使用扰付,加密等等堤撵。

數(shù)據(jù)模型(model)

Realm的數(shù)據(jù)模型是用傳統(tǒng)的Objective-C 接口interface@properties定義的。 就只要定義RLMObject的一個(gè)子類subclass或者一個(gè)現(xiàn)成的模型類羽莺,你就能輕松創(chuàng)建一個(gè)Realm的數(shù)據(jù)模型對(duì)象data model object实昨。Realm模型對(duì)象和其他的objective-c的功能很相似–你可以給它們添加你自己的方法method和協(xié)議protocol然后和其他的對(duì)象一樣使用。
唯一的限制就是從它們被創(chuàng)建開始盐固,只能在一個(gè)線程中被使用荒给。
如果你已經(jīng)安裝了我們的Xcode插件 那么,在New File對(duì)話框中會(huì)有一個(gè)很漂亮的樣板刁卜,你可以用它來創(chuàng)建interfaceimplementation文件志电。
你只需要為對(duì)象列表添加目標(biāo)類型的屬性property或者RLMArray的,就可以創(chuàng)建數(shù)據(jù)庫(kù)關(guān)聯(lián)和嵌套數(shù)據(jù)結(jié)構(gòu)
<code>
#import <Realm/Realm.h>
@class Person;
// Dog model
@interface Dog : RLMObject
@property NSString *name;
@property Person *owner;
@end
RLM_ARRAY_TYPE(Dog) // define RLMArray<Dog>
// Person model
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthdate;
@property RLMArray<Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // define RLMArray<Person>
// Implementations
@implementation Dog
@end // none needed
@implementation Person
@end // none needed
</code>

RLMObject的相關(guān)細(xì)節(jié).

屬性property種類
Realm支持以下的屬性property種類: BOOL,bool, int, NSInteger, long, float, double, CGFloat, NSString, NSDateNSData蛔趴。
你可以使用RLMArray<NSObject>RLMObject來模擬對(duì)一或?qū)Χ嗟年P(guān)系
Realm也支持RLMObject繼承挑辆。
屬性property特性
請(qǐng)注意Realm忽略了objective-cproperty attributes,像nonatomic, atomic, strong, copy, weak等等。
所以孝情,為了避免誤解鱼蝉,我們推薦你在寫入模型的時(shí)候不要使用任何的property attributes。但是箫荡,假如你設(shè)置了魁亦,這些attributes會(huì)一直生效直到RLMObject被寫入realm數(shù)據(jù)庫(kù)。
無論RLMObject在或不在realm中羔挡,你為gettersetter自定義的名字都能正常工作洁奈。

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

幾個(gè)存在的類方法進(jìn)一步指定模型信息:
+attributesForProperty:可以被重寫來來提供特定屬性property的屬性值attrbutes例如某個(gè)屬性值要添加索引。
+defaultPropertyValues可以被重寫婉弹,用以為新建的對(duì)象提供默認(rèn)值睬魂。
+primaryKey可以被重寫來設(shè)置模型的主鍵。定義主鍵可以提高效率并且確保唯一性镀赌。
ignoredProperties可以被重寫來防止Realm存儲(chǔ)模型屬性氯哮。

存儲(chǔ)對(duì)象

對(duì)對(duì)象的所有更改(添加,修改 和刪除)都必須通過寫入事務(wù)完成喉钢。
Realm的對(duì)象可以被實(shí)例化并且被單獨(dú)使用,和其他常規(guī)對(duì)象無異肠虽。
如果你想要在多個(gè)線程中共享或者永久保存以重復(fù)使用對(duì)象玛追,你必須將其存儲(chǔ)到Realm數(shù)據(jù)庫(kù)中——這個(gè)操作必須在寫事務(wù)中完成税课。 你可以參照如下代碼添加一個(gè)對(duì)象:
創(chuàng)建一個(gè)對(duì)象
Person *author = [[Person alloc] init]; author.name = @"David Foster Wallace";
獲取一個(gè)默認(rèn)realm對(duì)象
RealmRLMRealm *realm = [RLMRealm defaultRealm];
你只須這么做一次(單線程操作) Add to Realm with transaction
<code>
[realm beginWriteTransaction];
[realm addObject:author];
[realm commitWriteTransaction];
</code>
等到你把這個(gè)對(duì)象添加到realm數(shù)據(jù)庫(kù)里面之后, 你可以在多個(gè)線程里面共享之闲延。
并且從現(xiàn)在開始,你所做的每一次更改(必須在一個(gè)寫事務(wù)中完成)也會(huì)被永久儲(chǔ)存韩玩。
等到寫事務(wù)完成垒玲,這個(gè)更改將對(duì)所有共享這個(gè)Realm數(shù)據(jù)庫(kù)的線程可見。
需要注意的是找颓,寫入操作會(huì)相互阻塞合愈,而且其相對(duì)應(yīng)的進(jìn)程也會(huì)受到影響。
這和其他的永久數(shù)據(jù)存儲(chǔ)解決方案是一樣的击狮,所以我們建議你使用常用的佛析,也是最有效的方案, 將所有寫入放到一個(gè)單獨(dú)的進(jìn)程中彪蓬。
還要注意的是寸莫,因?yàn)閞ealm的MVCC結(jié)構(gòu), 讀取并不會(huì) 因?yàn)橐粋€(gè)進(jìn)行中的寫事務(wù)而受到影響寞焙。
詳細(xì)內(nèi)容储狭,請(qǐng)閱讀RLMObject互婿。

查詢

所有的數(shù)據(jù)抓取都很簡(jiǎn)單捣郊,并且直到獲得數(shù)據(jù)之后才創(chuàng)建副本。
關(guān)于使用RLMResults的小貼士:
Realm的對(duì)象查詢返回一個(gè)RLMResults對(duì)象慈参。它包含了一系列的RLMObject呛牲。
RLMResults有一個(gè)與NSArray很相似的interface(接口)并且對(duì)象可以通過索引(index)下標(biāo)獲取。
但不同于NSArrays的是驮配,RLMResult是歸類的——它只能容納一種RLMObjects類型娘扩。
根據(jù)種類獲取對(duì)象從realm中獲取對(duì)象的最基本方法就是 [RLMObject allObjects], 它返回一個(gè)RLMResults,里面是查詢的子類的所有RLMObject實(shí)例壮锻。
// 默認(rèn)查詢 RealmRLMResults *dogs = [Dog allObjects]; // 從默認(rèn)Realm中查找所有的??
<code>
// 指定查詢
RealmRLMRealm *petsRealm = [RLMRealm realmWithPath:@"pets.realm"]; // 得到一個(gè)指定的realm
RealmRLMResults *otherDogs = [Dog allObjectsInRealm:petsRealm]; // 在指定的realm中查詢所有的狗
</code>

謂詞/條件查詢

如果你對(duì) NSPredicate很熟悉的話, 那么你就已經(jīng)知道怎么在realm里面查詢了琐旁。
RLMObjects, RLMRealm, RLMArrayRLMResults都提供很好的methods來查詢特定的RLMObjects
你只需要傳遞相應(yīng)地NSPredicate實(shí)例,謂詞字符串猜绣,謂詞格式字符串灰殴,就可以獲取你想要的RLMObjects實(shí)例。就和NSObject一樣的掰邢。
舉個(gè)例子牺陶,下面的代碼就是對(duì)上面的拓展。 通過調(diào)用[RLMObject objectsWhere:],獲得了默認(rèn)realm數(shù)據(jù)庫(kù)中的所有顏色是黃褐色的辣之,名字開頭是“B”的狗的實(shí)例掰伸。
<code>
// 條件查詢
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];
</code>
可以參看Apple的Predicates Programming Guide 了解更多關(guān)于如何創(chuàng)建謂詞。
Realm支持很多常見的謂詞:在比較中怀估, 操作數(shù)可以是屬性名或者常量狮鸭。但是其中至少有一個(gè)是屬性名合搅。
只有int, long, float, double, and NSDate這些屬性類型(property types)支持 ==, <=, <, >=, >, !=, 和 BETWEEN這些比較操作符。布爾屬性可以支持==和歧蕉!=历筝。
在NSString和NSData屬性中, 我們支持的操作符有 ==, !=, BEGINSWITH, CONTAINS和ENDSWITH。
realm還支持如下的復(fù)合型操作符: AND廊谓, OR梳猪, NOT注意,我們雖然不支持aggregate expression type,但是我們支持BETWEEN操作符, 例如:
RLMResults *results = [Person objectsWhere:@"age BETWEEN %@", @[42, 43]];
詳詢[RLMObject objectsWhere:].

條件排序

在很多情況下蒸痹,我們都希望獲取或者查詢返回的結(jié)果都能按照一定條件排序春弥。
所以,RLMArray支持使用指定的屬性對(duì)數(shù)據(jù)列進(jìn)行排序叠荠。
Realm允許你指定一個(gè)排序要求并且根據(jù)一個(gè)或多個(gè)屬性進(jìn)行排序匿沛。
舉例來說, 下面代碼呼叫了[RLMObject objectsWhere:where:]對(duì)返回的數(shù)據(jù)”dogs”進(jìn)行排序榛鼎,排序的條件是名字的字母表升序逃呼。:
<code>
// Sort tan dogs with names starting with "B" by name
RLMResults *sortedDogs = [[Dog objectsWhere:
@"color = 'tan' AND name BEGINSWITH 'B'"] sortedResultsUsingProperty:@"name" ascending:YES];
</code>

鏈?zhǔn)讲樵?/h6>

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

Realm數(shù)據(jù)庫(kù)

默認(rèn)的realm數(shù)據(jù)庫(kù)

你可能已經(jīng)注意到了我們總是通過[RLMRealm defaultRealm]來獲得realm數(shù)據(jù)庫(kù)推姻。
這個(gè)method返回一個(gè)RLMRealm對(duì)象,指向一個(gè)叫做”default.realm“的文件框沟。
這個(gè)文件在你的app的Documents文件夾里面藏古。

其他的realm數(shù)據(jù)庫(kù)

有的時(shí)候擁有多個(gè)分離的數(shù)據(jù)庫(kù)是非常有必要的。
例如忍燥,如果你需要綁定數(shù)據(jù)到一個(gè)App拧晕,你可以打開另一個(gè)只讀的Realm數(shù)據(jù)庫(kù),參考[RLMRealm realmWithPath:]
[RLMRealm realmWithPath:readOnly:error:]
請(qǐng)注意傳遞到[RLMRealm realmWithPath:]的路徑必須是有寫入權(quán)限的梅垄。
存儲(chǔ)可寫Realm數(shù)據(jù)庫(kù)的最常用路徑就是iOS的“Documents”和OSX的“Application Support”厂捞。

跨線程使用數(shù)據(jù)庫(kù)

在不同的線程間使用同一個(gè)Realm數(shù)據(jù)庫(kù),你必須呼叫[RLMRealm defaultRealm],[RLMRealm realmWithPath:]或者 [RLMRealm realmWithPath:readOnly:eror:]以得到個(gè)線程相對(duì)應(yīng)的realm對(duì)象哎甲。
只要你路徑一致蔫敲,所有的RLMRealm對(duì)象指向的文件就一致。
我們還支持跨線程共享RLMRealm對(duì)象炭玫。

純內(nèi)存數(shù)據(jù)庫(kù)

正常的Realm數(shù)據(jù)庫(kù)是存儲(chǔ)在硬盤上的奈嘿, 但你也可以通過使用
[RLMRealm inMemoryRealmWithIdentifier:]來創(chuàng)建一個(gè)純內(nèi)存數(shù)據(jù)庫(kù)。
<code>
RLMRealm *realm = [RLMRealm inMemoryRealmWithIdentifier:@"MyInMemoryRealm"];
</code>
純內(nèi)存數(shù)據(jù)庫(kù)在每次程序退出時(shí)不會(huì)保存數(shù)據(jù)吞加。
但是裙犹,這不會(huì)妨礙到realm的其他功能尽狠,包括請(qǐng)求,關(guān)系和線程安全叶圃。
假如你需要靈活的數(shù)據(jù)讀寫但又不想永久儲(chǔ)存袄膏,那么純內(nèi)存數(shù)據(jù)庫(kù)對(duì)你來說一定大有裨益。
注意: 如果某個(gè)純內(nèi)存Realm實(shí)例沒有被引用掺冠,所有的數(shù)據(jù)就會(huì)被釋放沉馆。
強(qiáng)烈建議你在app中用強(qiáng)引用來鉗制所有新建的純內(nèi)存Realm數(shù)據(jù)庫(kù)。

關(guān)系

可以通過使用RLMObject 和 RLMArrayproperties互相聯(lián)結(jié)德崭。
假如說你預(yù)先定義了一個(gè)”人“模型(see above)斥黑,我們?cè)賮韯?chuàng)建一個(gè)”狗“模型。:
<code>
// Dog.h
@interface Dog : RLMObject
@property NSString *name;
@end
</code>

對(duì)一

對(duì)于多對(duì)一和一對(duì)一關(guān)系眉厨, 僅僅只需要定義一個(gè)RLMObject子類類型的property:
<code>
// Dog.h
@interface Dog : RLMObject...
// other property declarations
@property Person *owner;
@end
</code>
你可以像往常一樣使用之:
<code>
Person *jim = [[Person alloc] init];
Dog *rex = [[Dog alloc] init];
rex.owner = jim;
</code>
當(dāng)你使用RLMObject properties锌奴,你可以通過正常的property語法獲取嵌套屬性。
例如rex.owner.address.country會(huì)遍歷這個(gè)對(duì)象圖來獲得你所想要的子類憾股。

對(duì)多

你可以通過使用RLMArrayproperties來定義一個(gè)對(duì)多關(guān)系鹿蜀。
RLMArrays包含多個(gè)同類的RLMObjects,并且擁有一個(gè)和NSMutableArray非常相似的interface(接口)服球。
如果想要把”dogs“(多個(gè)”Dog“)屬相添加到”Person“模型中來茴恰,我們必須定義一個(gè)RLMArray ————這可以通過在相應(yīng)的模型(model)interface中添加一個(gè)宏(macro)來實(shí)現(xiàn)。
<code>
//Dog.h
@interface Dog : RLMObject...
// property declarations
@end
RLM_ARRAY_TYPE(Dog)
// Defines an RLMArraytype
</code>
然后你可以定義屬性有咨,類型為RLMArray琐簇。
<code>
// Person.h
@interface Person : RLMObject...
// other property declarations
@property RLMArray*dogs;
@end
</code>
我們又可以像往常一樣讀取和賦值啦蒸健。
<code>
// Jim is owner of Rex and all dogs named "Fido"
RLMArray *someDogs = [Dog objectsWhere:@"name contains 'Fido'"];
[jim.dogs addObjects:someDogs];
[jim.dogs addObject:rex];
</code>

通知

每當(dāng)一次寫事務(wù)完成Realm實(shí)例都會(huì)向其他線程上的實(shí)例發(fā)出通知座享,可以通過注冊(cè)一個(gè)block來響應(yīng)通知:
<code>
// Observe Realm Notifications
self.token = [realm addNotificationBlock:^(NSString *note, RLMRealm * realm) {
[myViewController updateUI];
}];
</code>
只要有任何的引用指向這個(gè)返回的notification token,它就會(huì)保持激活狀態(tài)似忧。
在這個(gè)注冊(cè)更新的類里渣叛,你需要有一個(gè)強(qiáng)引用來鉗制這個(gè)token, 因?yàn)橐坏﹏otification token被釋放盯捌,通知也會(huì)自動(dòng)解除注冊(cè)淳衙。
具體內(nèi)容:
[Realm addNotificationBlock:][Realm removeNotificationBlock:]

后臺(tái)操作

通過把大量的寫入放入到一個(gè)大型事務(wù)中饺著,Realm可以大大的提高大型數(shù)據(jù)讀取的運(yùn)行效率箫攀。
事務(wù)可以在后臺(tái)通過GCD運(yùn)行,這樣可以避免阻塞主進(jìn)程幼衰。
RLMRealm并不是線程安全的靴跛,所以你必須在每一個(gè)你需要讀寫的進(jìn)程或者調(diào)度隊(duì)列中添加RLMRealm實(shí)例。
這里有一個(gè)在后臺(tái)隊(duì)列中添加百萬級(jí)數(shù)據(jù)的例子渡嚣。

dispatch_async(queue, ^{
    // Get realm and table instances for this thread
    RLMRealm *realm = [RLMRealm defaultRealm];
    // Break up the writing blocks into smaller portions
    // by starting a new transaction
    for (NSInteger idx1 = 0; idx1 < 1000; idx1++) {
        [realm beginWriteTransaction];
        // Add row via dictionary. Property order is ignored.
            for (NSInteger idx2 = 0; idx2 < 1000; idx2++) {
                  [Person createInRealm:realm withObject:@{@"name":[self randomString],@"birthdate":[self randomDate]}];
             }
    // Commit the write transaction
    // to make this data available to other threads
    [realm commitWriteTransaction];
    }
});

可以參考RLMRealm梢睛。

REST APIs<p>

Realm輕松的整合了REST API肥印, 這使得Realm在幾個(gè)方面勝過了無本地緩存的REST API:
Realm緩存數(shù)據(jù)使得你能提供離線體驗(yàn),普通的REST API無法做到這一點(diǎn)——他們一定需要網(wǎng)絡(luò)連接绝葡。
通過在本地存儲(chǔ)你的整個(gè)數(shù)據(jù)集深碱,你可以在本地進(jìn)行查詢,這能提供比普通REST API好很多的本地搜索體驗(yàn)藏畅。
可直接從Realm查詢數(shù)據(jù)敷硅,不必等待服務(wù)器端復(fù)雜的API處理。
減輕服務(wù)器端負(fù)荷愉阎,只需要在更新和修改數(shù)據(jù)時(shí)進(jìn)行必要的訪問竞膳。

最佳操作

異步請(qǐng)求
網(wǎng)絡(luò)請(qǐng)求和其他一些操作應(yīng)該放到后臺(tái),以免影響交互效果诫硕。同理Realm數(shù)據(jù)庫(kù)中大規(guī)模插入和修改應(yīng)該在后臺(tái)進(jìn)行坦辟。你可以用通知來相應(yīng)后臺(tái)操作。
緩存數(shù)據(jù)庫(kù)大于用戶當(dāng)下查詢
我們建議你對(duì)可能使用的數(shù)據(jù)進(jìn)行預(yù)處理并且存儲(chǔ)到Realm中章办。 這么做可以讓你在本地?cái)?shù)據(jù)集中進(jìn)行查詢锉走。
插入或更新
如果你的數(shù)據(jù)集有一個(gè)特有的標(biāo)識(shí)符, 例如一個(gè)主鍵藕届, 你可以用它來判定插入還是更新挪蹭。只需要使用[RLMObject createOrUpdateInDefaultRealmWithObject:];如果你從API得到響應(yīng), 這個(gè)method會(huì)從Realm中查詢這個(gè)響應(yīng)是否有記錄休偶。

如果在本地有記錄梁厉, 就可以從響應(yīng)中根據(jù)最新的數(shù)據(jù)進(jìn)行更新。如果沒有踏兜,就將該響應(yīng)插入到Realm數(shù)據(jù)庫(kù)中词顾。
示例
以下是一個(gè)如何應(yīng)用一個(gè)使用了REST API的Realm的示例。在這個(gè)示例里碱妆,我們將從foursquare API里獲取一組JSON格式的數(shù)據(jù)肉盹,然后將它以Realm Objects的形式儲(chǔ)存到默認(rèn)realm數(shù)據(jù)庫(kù)里。 如果你想?yún)⒖碱愃剖纠膶?shí)際操作疹尾,請(qǐng)觀看 video demo.

首先我們要?jiǎng)?chuàng)建一個(gè)默認(rèn)Realm數(shù)據(jù)庫(kù)的實(shí)例上忍,用于存儲(chǔ)數(shù)據(jù)以及從 API 獲取數(shù)據(jù)。為了更簡(jiǎn)單易讀纳本,我們?cè)谶@個(gè)例子里面運(yùn)動(dòng)了
[NSData initWithContentsOfURL].
// Call the API NSData *response = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:@"https://api.foursquare.com/v2/venues/search?near=San%20Francisco&limit=50"]]; // Deserialize the response to JSON NSDictionary *json = [[NSJSONSerialization JSONObjectWithData:response options:kNilOptions error:&error] objectForKey:@"response"];

這條響應(yīng)包含了JSON數(shù)組窍蓝,形式類似于:
<code>
{
"venues": [{"id": "4c82f252d92ea09323185072",
"name": "Golden Gate Park",
"contact": {"phone": "4152522590"},
"location": {"lat": 37.773835608329,"lng": -122.41962432861,"postalCode": "94103","cc": "US","state": "California","country": "United States"}
}]
}
</code>
要想把JSON數(shù)據(jù)導(dǎo)入Realm中我們有很多辦法,殊途同歸繁成。你可以讀取 NSDictionary然后將其屬性通過插入功能手動(dòng)映射到一個(gè)RLMObject上吓笙。

為了演示效果,在這個(gè)示例里朴艰,我們將直接把 NSDictionary插入到Realm中观蓄,然后讓Realm自動(dòng)快速將其屬性映射到RLMObject上混移。

為了確保示例能夠成功,我們需要一個(gè)屬性完全匹配JSON數(shù)據(jù)特點(diǎn)的RLMObject的框架侮穿。JSON數(shù)據(jù)特點(diǎn)如果得不到匹配歌径,將在植入時(shí)自動(dòng)被忽略。

以下RLMObject的定義是有效的:

// Contact.h
@interface Contact : RLMObject
@property NSString *phone;
@end
@implementation Contact
+ (NSString)primaryKey {
return @"phone";
}
@end
RLM_ARRAY_TYPE(Contact)
// Location.h
@interface Location : RLMObject
@property double lat; // latitude
@property double lng; // longitude
@property NSString *postalCode;
@property NSString *cc;
@property NSString *state;
@property NSString *country;
@end
@implementation Location
@end
RLM_ARRAY_TYPE(Location)
// Venue.h
@interface Venue : RLMObject
@property NSString *id;
@property NSString *name;
@property Contact  *contact;
@property Location *location;
@end
@implementation Venue
+ (NSString)primaryKey {
return @"id";
}
@end
RLM_ARRAY_TYPE(Venue)

因?yàn)榻Y(jié)果集是以數(shù)組的形式給我們的亲茅,我們要呼叫
[Venue createInDefaultRealmWithObject:]來為每個(gè)元素創(chuàng)建一個(gè)對(duì)象. 這里會(huì)創(chuàng)建 Venue 和一個(gè)JSON格式的子對(duì)象回铛,并將這些新建的對(duì)象加入到默認(rèn)realm數(shù)據(jù)庫(kù)中:

//Extract the array of venues from the response
NSArray *venues = json[@"venues"];
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
// Save one Venue object (and dependents) for each element of the array
for (NSDictionary *venue in venues) {
[Venue createOrUpdateInDefaultRealmWithObject:venue];
}
[realm commitWriteTransaction];

數(shù)據(jù)庫(kù)遷移

當(dāng)你和數(shù)據(jù)庫(kù)打交道的時(shí)候,時(shí)不時(shí)的你需要改變數(shù)據(jù)模型(model)克锣,但因?yàn)镽ealm中得數(shù)據(jù)模型被定義為標(biāo)準(zhǔn)的Objective-C interfaces茵肃,要改變模型,就像改變其他Objective-C interface一樣輕而易舉袭祟。舉個(gè)例子验残,假如我們有如下的interface, 叫“Person.h”:

@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end

我們想要更新數(shù)據(jù)模型巾乳,因?yàn)槲覀円砑右粋€(gè)“全名”(fullname)屬性您没, 而不是用分開的“姓”+“名”。要達(dá)到這樣的目的胆绊,我們只需要改變對(duì)象的interface氨鹏,如下:

@interface Person : RLMObject
@property NSString *fullName;
@property int age;
@end

在這個(gè)時(shí)候如果你保存了數(shù)據(jù),那么Realm就會(huì)注意到代碼和硬盤數(shù)據(jù)不匹配压状。 每當(dāng)這時(shí)仆抵,你必須對(duì)數(shù)據(jù)構(gòu)架進(jìn)行遷移,否則就會(huì)有錯(cuò)誤拋出种冬。

進(jìn)行遷移

你可以通過呼叫[RLMRealm setSchemaVersion:withMigrationBlock:]自定義數(shù)據(jù)遷移以及相應(yīng)的構(gòu)架版本镣丑。
你的數(shù)據(jù)遷移模塊將會(huì)為你提供相應(yīng)地邏輯,用來更新數(shù)據(jù)構(gòu)架碌廓。呼叫[RLMRealm setSchemaVersion:withMigrationBlock:]之后, 任何需要遷移的Realm數(shù)據(jù)庫(kù)都會(huì)自動(dòng)使用指定的遷移模塊并且更新到相應(yīng)地版本传轰。

例如,假設(shè)我們想要把之前‘Person’的子類遷移谷婆,如下所示是最簡(jiǎn)化的數(shù)據(jù)遷移組:

// Inside your [AppDelegate didFinishLaunchingWithOptions:]
// Notice setSchemaVersion is set to 1, this is always set manually. It must be
// higher than the previous version (oldSchemaVersion) or an RLMException is thrown

[RLMRealm setSchemaVersion:1 forRealmAtPath:[RLMRealm defaultRealmPath] withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) {
// We haven’t migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
    // Nothing to do!
    // Realm will automatically detect new properties and removed properties
    // And will update the schema on disk automatically
    }
}];
// now that we have called `setSchemaVersion:withMigrationBlock:`, opening an outdated
// Realm will automatically perform the migration and opening the Realm will succeed
[RLMRealm defaultRealm];

我們所需要做的就是用一個(gè)空模塊更新版本,表明這個(gè)構(gòu)架已經(jīng)被Realm自動(dòng)更新了辽聊。

雖然這是系統(tǒng)能接受的最簡(jiǎn)化的遷移纪挎,我們應(yīng)當(dāng)用有意義的代碼來填充這些新的屬性(這里就是“fullname”)。在數(shù)據(jù)遷移模塊中跟匆,我們可以呼叫[RLMMigration enumerateObjects:block:] 來列舉某種格式的每一個(gè)Realm文件异袄,并執(zhí)行必要的遷移判定:

// Inside your [AppDelegate didFinishLaunchingWithOptions:]

[RLMRealm setSchemaVersion:1 forRealmAtPath:[RLMRealm defaultRealmPath] withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) {
// We haven’t migrated anything yet, so oldSchemaVersion == 0
    if (oldSchemaVersion < 1) {
    // The enumerateObjects:block: method iterates
    // over every 'Person' object stored in the Realm file
    [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
        // combine name fields into a single field
        newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
        oldObject[@"firstName"],
       oldObject[@"lastName"]];
      }];
    }
}];

一旦遷移成功結(jié)束,Realm和其所有文件即可被你的app正常存取玛臂。

添加更多的版本


假如說現(xiàn)在我們有兩個(gè)之前版本的Person類:

// v0
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end
// v1
@interface Person : RLMObject
@property NSString *fullName; // new property
@property int age;
@end
// v2
@interface Person : RLMObject
@property NSString *fullName;
@property NSString *email;  // new property
@property int age;
@end

我們的遷移模塊里面的邏輯大致如下:

[RLMRealm setSchemaVersion:2 forRealmAtPath:[RLMRealm defaultRealmPath]
withMigrationBlock:^(RLMMigration *migration,
NSUInteger oldSchemaVersion) {
// The enumerateObjects:block: method iterates
// over every 'Person' object stored in the Realm file
[migration enumerateObjects:Person.className
block:^(RLMObject *oldObject, RLMObject *newObject) {
// Add the 'fullName' property only to Realms with a schema version of 0
if (oldSchemaVersion < 1) {
newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
oldObject[@"firstName"],
oldObject[@"lastName"]];
}
// Add the 'email' property to Realms with a schema version of 0 or 1
if (oldSchemaVersion < 2) {
newObject[@"email"] = @"";
}
}];
}];
// now that we have called `setSchemaVersion:withMigrationBlock:`, opening an outdated
// Realm will automatically perform the migration and opening the Realm will succeed
[RLMRealm defaultRealm];

想要了解更多關(guān)于數(shù)據(jù)庫(kù)的框架遷移烤蜕, 參見migration sample app.

Linear Migrations

假如說封孙,我們的app有兩個(gè)用戶: JP和Tim. JP經(jīng)常更新app,但Tim卻經(jīng)常跳過讽营。 所以JP可能下載過這個(gè)app的每一個(gè)版本虎忌,并且一步一步的跟著更新構(gòu)架:他下載第一次更新,從v0到v1橱鹏, 第二次更新從v1到v2膜蠢,以此類推,井然有序莉兰。相反挑围,Tim很有可能直接從v0跳到了v2。 所以糖荒,你應(yīng)該使用非嵌套的 if (oldSchemaVersion < X)結(jié)構(gòu)來構(gòu)造你的數(shù)據(jù)庫(kù)遷移模塊杉辙,以確保不管他們是在使用哪個(gè)版本的構(gòu)架,都能看見所有的更新捶朵。

當(dāng)你的用戶不按規(guī)則出牌奏瞬,跳過有些更新版本的時(shí)候,另一種情況也會(huì)發(fā)生泉孩。 假如你在v2里刪掉了一個(gè)“email”屬性硼端,然后在v3里又把它重新引進(jìn)了。假如有個(gè)用戶從v1直接跳到v3寓搬,那Realm不會(huì)自動(dòng)檢測(cè)到v2的這個(gè)刪除操作因?yàn)榇鎯?chǔ)的數(shù)據(jù)構(gòu)架和代碼中的構(gòu)架吻合珍昨。這會(huì)導(dǎo)致Tim的Person對(duì)象有一個(gè)v3的email property,但里面的內(nèi)容卻是v1的句喷。這個(gè)看起來沒什么大問題镣典,但是假如兩者的內(nèi)部存儲(chǔ)類型不同(比如說: 從ISO email representation 變成了自定義),那麻煩就大了唾琼。為了避免這種不必要的麻煩兄春,我們推薦你在if (oldSchemaVersion < 3)中,nil out所有的email property锡溯。

下一步

你可以看一下我們的我們給出的示例赶舆。看看在app中應(yīng)該如何使用realm(我們已經(jīng)有越來越多的樣本了<婪埂)

做一個(gè)愉快地碼農(nóng)芜茵!你也總是可以在realm-cocoa上實(shí)時(shí)的和其他開發(fā)者聊天。

當(dāng)前的限制


realm現(xiàn)在還是beta版本倡蝙。我們還在為1.0的發(fā)布一直不斷的添加新特性九串,修復(fù)bug。我們整理了一些普遍存在的限制
如果你想要看到完整地issue列表, 參見GitHub issues猪钮。

Realm CocoaPods 不支持Swift 項(xiàng)目開發(fā)

CocoaPods 暫時(shí)還不支持Swift 項(xiàng)目開發(fā)(戳這個(gè)GitHub issue #2222). 想要在一個(gè)Swift 項(xiàng)目中使用Realm品山,請(qǐng)參見上面的步驟.

暫時(shí)不支持通知細(xì)節(jié)

雖然要在realm發(fā)生變化的時(shí)候可以接到通知 (參見 通知), 但現(xiàn)在我們還不能從notification里面得知什么東西被添加/刪減/移動(dòng)/更新了。 我們會(huì)盡快完善這個(gè)功能的烤低。

NSDate在秒的地方被截?cái)?/h6>

一個(gè)包含非整秒數(shù)的NSDate在存入realm的時(shí)候肘交,會(huì)在秒的地方被截?cái)唷N覀冋谛迯?fù)這個(gè)問題拂玻。 可參考 GitHub issue #875酸些。同時(shí),你可以無損存儲(chǔ)NSTimeInterval格式檐蚜。

Realm對(duì)象的Setters & Getters不能被重寫

因?yàn)镽ealm重寫了setters和getters魄懂, 所以你不可以在你的對(duì)象上再重寫。一個(gè)簡(jiǎn)單的替代方法就是:創(chuàng)建一個(gè)新的realm-ignored屬性(它的accessors可以被重寫闯第, 并且可以呼叫其他的getter和setter)市栗。

不支持 KVO

Realm不支持KVO, 但它有自己的通知機(jī)制(see 通知).
Realm文件不能被兩個(gè)進(jìn)程同時(shí)訪問
盡管Realm文件可以在多個(gè)線程中被同時(shí)訪問咳短, 它們每次只能被一個(gè)進(jìn)程訪問填帽。這對(duì)iOS 8和OSX應(yīng)用有影響。不同的進(jìn)程應(yīng)該復(fù)制或者新建Realm文件咙好。 敬請(qǐng)期待多進(jìn)程支持篡腌。
<p>

FAQ


realm的支持庫(kù)有多大?

一旦你的app編譯完成勾效, realm的支持庫(kù)應(yīng)該只有1 MB左右嘹悼。 我們發(fā)布的那個(gè)可能有點(diǎn)大(iOS ~37MB, OSX ~2.4MB), 那是因?yàn)樗鼈冞€包含了對(duì)其他構(gòu)架的支持(ARM层宫, ARM64杨伙,模擬器的是X86)和一些編譯符號(hào)。 這些都會(huì)在你編譯app的時(shí)候被Xcode自動(dòng)清理掉萌腿。

我應(yīng)該在正式產(chǎn)品中使用realm嗎限匣?

自2012年起, realm就已經(jīng)開始被用于正式的商業(yè)產(chǎn)品中了毁菱。
正如你預(yù)期米死,我們的objective-c & Swift API 會(huì)隨著社區(qū)的反饋不斷的完善和進(jìn)化。 所以鼎俘,你也應(yīng)該期待realm帶給你更多的新特性和版本修復(fù)哲身。

我該如何保護(hù)Realm里面的數(shù)據(jù)?

Realm 有幾種加密方法贸伐, 各有千秋。參考這個(gè)Github評(píng)論怔揩。Realm將在未來支持跨平臺(tái)加密捉邢。

我要付realm的使用費(fèi)用嗎脯丝?

不要, Realm的徹底免費(fèi)的伏伐, 哪怕你用于商業(yè)軟件宠进。

你們計(jì)劃怎么賺錢?

其實(shí)藐翎,我們靠著我們的技術(shù)材蹬,已經(jīng)開始賺錢啦!這些錢來自于我們銷售企業(yè)級(jí)產(chǎn)品的利潤(rùn)吝镣。如果你想要得到比普通發(fā)行版本或者realm-cocoa更多的支持堤器, 我們很高興和你發(fā)郵件聊聊。 我們一直致力于開發(fā)開源的(Apache 2.0)末贾,免費(fèi)的realm-cocoa闸溃。

我看到你們?cè)诖a里有“tightdb”或者“core”, 那是個(gè)啥拱撵?

TightDB是我們的C++存儲(chǔ)引擎的舊名辉川。core 現(xiàn)在還沒有開源但我們的確想這樣做(依舊使用Apache2.0)假如我們有時(shí)間來進(jìn)行清理,重命名等工作拴测。同時(shí)乓旗,它的二進(jìn)制發(fā)行版在Realm Core(tightDB)Binary License里面可以找到。

訂閱我們定期發(fā)布的community newsletter集索。

里面有一些非常有用的提示和其他的用例屿愚。當(dāng)有新的Realm博客或者教程出現(xiàn),郵件也會(huì)通知你抄谐。StackOverflow: 查找之前的有#realm標(biāo)簽的問答渺鹦, — 或者,開一個(gè)新的蛹含。
推特: 聯(lián)系@realm 或者用#realm標(biāo)簽毅厚。
Email: docs/cocoa/latest realm-cocoa@googlegroups.com.
官網(wǎng)鏈接:https://realm.io

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市浦箱,隨后出現(xiàn)的幾起案子吸耿,更是在濱河造成了極大的恐慌,老刑警劉巖酷窥,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咽安,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蓬推,警方通過查閱死者的電腦和手機(jī)妆棒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人糕珊,你說我怎么就攤上這事动分。” “怎么了红选?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵澜公,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我喇肋,道長(zhǎng)坟乾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任蝶防,我火速辦了婚禮甚侣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慧脱。我一直安慰自己渺绒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布菱鸥。 她就那樣靜靜地躺著宗兼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪氮采。 梳的紋絲不亂的頭發(fā)上殷绍,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音鹊漠,去河邊找鬼主到。 笑死,一個(gè)胖子當(dāng)著我的面吹牛躯概,可吹牛的內(nèi)容都是我干的登钥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼娶靡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牧牢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姿锭,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤塔鳍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后呻此,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轮纫,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年焚鲜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掌唾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片放前。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖郑兴,靈堂內(nèi)的尸體忽然破棺而出犀斋,到底是詐尸還是另有隱情贝乎,我是刑警寧澤情连,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站览效,受9級(jí)特大地震影響却舀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锤灿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一挽拔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧但校,春花似錦螃诅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亭枷,卻和暖如春袭艺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叨粘。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工猾编, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人升敲。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓答倡,卻偏偏與公主長(zhǎng)得像帅容,于是被迫代替她去往敵國(guó)和親蜘澜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓶佳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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