Realm 在 iOS 中的使用方法及注意事項(xiàng)

Objective?C版本的 Realm 能夠讓您以一種安全悄雅、耐用以及迅捷的方式來高效地編寫應(yīng)用的數(shù)據(jù)模型層

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

Realm數(shù)據(jù)模型是基于標(biāo)準(zhǔn) Objective?C 類來進(jìn)行定義的,使用屬性來完成模型的具體定義。通過簡單的繼承 RLMObject 或者一個(gè)已經(jīng)存在的模型類,您就可以創(chuàng)建一個(gè)新的 Realm 數(shù)據(jù)模型對象纽什。
Realm模型對象在形式上基本上與其他 Objective?C 對象相同 - 您可以給它們添加您自己的方法(method)和協(xié)議(protocol)枫慷,和在其他對象中使用類似探孝。
您只需要為對象的類型列表添加目標(biāo)類型的屬性足丢,或者 RLMArray栖疑,就可以創(chuàng)建數(shù)據(jù)關(guān)系(relationship)和嵌套數(shù)據(jù)結(jié)構(gòu)(nested data structure)。

#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;
@property RLMArray<Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // 定義RLMArray<Person>

支持的類型

Realm支持以下的屬性類型:BOOL int NSInteger long float double NSString NSDate NSData 以及 被特殊類型標(biāo)記的 NSNumber 。
您可以使用 RLMArray<Object *><Object>RLMObject 的子類來建立諸如一對多、一對一之類的關(guān)系模型。
在 Xcode 7 以及之后的版本中蜀细,RLMArray支持編譯時(shí)的 Objective?C 泛型(generics)塘娶。下面是不同屬性定義方法的意義以及用途:

// RLMArray: 屬性類型。
// <Object *>: 屬性的特別化(generic specialization)鸦难,這可以阻止在編譯時(shí)使用錯(cuò)誤對象類型的數(shù)組。
// <Object>: 此RLMArray遵守的協(xié)議,可以讓 Realm 知曉如何在運(yùn)行時(shí)確定數(shù)據(jù)模型的架構(gòu)。

關(guān)系(Relationships)

RLMObject 能夠借助 RLMObject 以及 RLMArray 屬性來和另一個(gè) RLMObject 建立聯(lián)系。 RLMArray 的接口和 NSArray 非常類似等太,在 RLMArray 中的對象能夠通過索引下標(biāo)(indexed subscripting)進(jìn)行訪問包颁。 與 NSArray 所不同的是,RLMArray 的類型是固定的,其中只能存放簡單的 RLMObject 子類類型。 要了解更詳細(xì)的信息,請參閱 RLMArray萄涯。
假設(shè)現(xiàn)在您已經(jīng)定義好了 Person 數(shù)據(jù)模型(見上文),讓我們創(chuàng)建另一個(gè)名為 Dog 的數(shù)據(jù)模型:

// Dog.h
@interface Dog : RLMObject
@property NSString *name;
@end

對一(To-One)關(guān)系

對于多對一(many-to-one)或者一對一(one-to-one)關(guān)系來說伯襟,只需要聲明一個(gè) RLMObject 子類類型的屬性即可:

// Dog.h
@interface Dog : RLMObject
// 其余屬性聲明...
@property Person *owner;
@end

您可以非常簡單的通過這個(gè)屬性完成關(guān)系的綁定:

Person *jim = [[Person alloc] init];
Dog *rex = [[Dog alloc] init];
rex.owner = jim;

當(dāng)使用 RLMObject 屬性的時(shí)候,您可以通過正常的屬性訪問語法來訪問嵌套屬性。比如說,rex.owner?.address.country 會依次讀取對象的屬性沮稚,然后自動從 Relam 中匹配所需的每一個(gè)對象盛杰。

對多(To-Many)關(guān)系

通過 RLMArray 類型的屬性您可以定義一個(gè)對多關(guān)系逗嫡。RLMArray 中可以包含簡單類型的 RLMObject 雷滚,其接口與 NSMutableArray 非常類似车份。

RLMArray 可能會包含多個(gè)相同 Realm 對象的引用严就,即便對象帶有主鍵也是如此铸董。例如,您或許會創(chuàng)建一個(gè)空的 RLMArray 沉衣,然后連續(xù)三次向其中插入同一個(gè)對象栋艳;當(dāng)使用 0、1吸占、2 的索引來訪問元素的時(shí)候晴叨,RLMArray 將會返回對應(yīng)的對象,而所返回的這三個(gè)對象都是同一個(gè)對象矾屯。

如果要給我們的 Person 數(shù)據(jù)模型添加一個(gè) “dogs” 屬性兼蕊,以便能夠和多個(gè) “dogs” 建立關(guān)系,也就是表明一個(gè)「人」可以養(yǎng)多條「狗」件蚕,那么我們首先需要定義一個(gè) RLMArray<Dog> 類型孙技。通過對應(yīng)數(shù)據(jù)模型接口文件下的宏命令即可完成:

//Dog.h
@interface Dog : RLMObject
// 屬性聲明...
@end

**
RLM_ARRAY_TYPE(Dog) // 定義一個(gè) RLMArray<Dog> 類型
RLM_ARRAY_TYPE 宏創(chuàng)建了一個(gè)協(xié)議产禾,從而允許 RLMArray<Dog> 語法的使用。如果該宏沒有放置在模型接口的底部的話牵啦,您或許需要提前聲明該模型類亚情。
**
接下來您就能定義RLMArray<Dog>類型的屬性了:

```objc
// Person.h
@interface Person : RLMObject
// 其余的屬性聲明...
@property RLMArray<Dog *><Dog> *dogs;
@end

您可以和之前一樣,對 RLMArray 屬性進(jìn)行訪問和賦值:

// jim 是 rex 以及所有名字叫“Fido”的狗狗的主人
RLMResults<Dog *> *someDogs = [Dog objectsWhere:@"name contains 'Fido'"];
[jim.dogs addObjects:someDogs];
[jim.dogs addObject:rex];

注意:雖然可以給 RLMArray 屬性賦值為 nil哈雏,但是這僅用于“清空”數(shù)組势似,而不是用以移除數(shù)組。這意味著您總是可以向一個(gè) RLMArray 屬性中添加對象僧著,即使其被置為了 nil履因。
RLMArray 屬性將確保其當(dāng)中的插入次序不會被擾亂。

這里需要強(qiáng)調(diào)的是嵌套數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)關(guān)系的使用盹愚,即對 RLMArray 的使用栅迄。RLMArray 是Realm的數(shù)組,只能存放對象類型的數(shù)據(jù)皆怕。在使用 RLMArray 時(shí)需要注意:RLM_ARRAY_TYPE 宏創(chuàng)建了一個(gè)協(xié)議毅舆,從而允許 RLMArray<Dog> 語法的使用。如果該宏沒有放置在模型接口的底部的話愈腾,您或許需要提前聲明該模型類憋活。

實(shí)用例

#import <Realm/Realm.h>

@interface BKUserPayWay : RLMObject

@property NSString *userPayWayName;
@property NSString *userPayWayValue;

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

@interface BKUserStatusInfo : RLMObject

@property NSString * userNum;
@property NSString * userPwd;
@property NSString * deveiceToken;

//有糖小店支付 信息
@property NSString *  userSecretKey;
@property NSString *  userValidTime;
@property RLMArray <BKUserPayWay *><BKUserPayWay>*  userPayWays;

反向關(guān)系(Inverse Relationship)

鏈接是單向性的。因此虱黄,如果對多關(guān)系屬性 Person.dogs 鏈接了一個(gè) Dog 實(shí)例悦即,而這個(gè)實(shí)例的對一關(guān)系屬性 Dog.owner 又鏈接到了對應(yīng)的這個(gè) Person 實(shí)例,那么實(shí)際上這些鏈接仍然是互相獨(dú)立的橱乱。為 Person 實(shí)例的 dogs 屬性添加一個(gè)新的 Dog 實(shí)例辜梳,并不會將這個(gè) Dog 實(shí)例的 owner 屬性自動設(shè)置為該 Person 。但是由于手動同步雙向關(guān)系會很容易出錯(cuò)泳叠,并且這個(gè)操作還非常得復(fù)雜作瞄、冗余,因此 Realm 提供了 “鏈接對象 (linking objects)” 屬性來表示這些反向關(guān)系危纫。

借助鏈接對象屬性宗挥,您可以通過指定的屬性來獲取所有鏈接到指定對象的對象。例如种蝶,一個(gè) Dog 對象可以擁有一個(gè)名為 owners 的鏈接對象屬性契耿,這個(gè)屬性中包含了某些 Person 對象,而這些 Person 對象在其 dogs 屬性中包含了這一個(gè)確定的 Dog 對象蛤吓。您可以將 owners 屬性設(shè)置為 RLMLinkingObjects 類型宵喂,然后重寫 +[RLMObject linkingObjectsProperties] 來指明關(guān)系糠赦,說明 ownders 中包含了 Person 模型對象会傲。

@interface Dog : RLMObject
@property NSString *name;
@property NSInteger age;
@property (readonly) RLMLinkingObjects *owners;
@end

@implementation Dog
+ (NSDictionary *)linkingObjectsProperties {
    return @{
        @"owners": [RLMPropertyDescriptor descriptorWithClass:Person.class propertyName:@"dogs"],
    };
}
@end

可空屬性(Optional Properties)

通常情況下锅棕,NSString *NSData * 以及 NSDate * 屬性可以設(shè)置為 nil淌山。如果你不需要實(shí)現(xiàn)此功能裸燎,你可以重寫您的 RLMObject 子類的 +requiredProperties
方法。

比如對于以下的模型定義來說泼疑,如果嘗試給 name 屬性設(shè)置為 nil
將會拋出一個(gè)異常,但是將 birthday 屬性設(shè)置為 nil
卻是允許的:

@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end

@implementation Person
+ (NSArray *)requiredProperties {
    return @[@"name"];
}
@end

存儲可空數(shù)字目前已經(jīng)可以通過 NSNumber * 屬性完成。
由于 Realm 對不同類型的數(shù)字采取了不同的存儲格式缓熟,因此設(shè)置可空的數(shù)字屬性必須是 RLMInt犀勒、RLMFloatRLMDouble 或者 RLMBool 類型会油。所有賦給屬性的值都會被轉(zhuǎn)換為其特定的類型个粱。

請注意:NSDecimalNumber 的值只能分配給類型為 RLMDouble 的 Realm 屬性,此外 Realm 將會存儲近似于雙精度浮點(diǎn)的數(shù)值翻翩,而不是存儲基本的十進(jìn)制數(shù)值都许。

比如說,如果我們存儲一個(gè)用戶的年齡(age)而不是存儲他們的生日嫂冻,同時(shí)還要允許當(dāng)您不知道該用戶的年齡的時(shí)候?qū)?age 屬性設(shè)置為 nil

@interface Person : RLMObject
@property NSString *name;
@property NSNumber<RLMInt> *age;
@end

@implementation Person
+ (NSArray *)requiredProperties {
    return @[@"name"];
}
@end

RLMProperty 的子類屬性始終都可以為 nil胶征,因此這些類型不能夠放在 requiredProperties 中,并且 RLMArray 不支持存儲 nil 值桨仿。

簡單說明

這個(gè)表格提供了關(guān)于聲明模型屬性的簡易參考:

類型 非可選值形式 可選值形式
Bool @property BOOL value; @property NSNumber<RLMBool> *value;
Int @property int value; @property NSNumber<RLMInt> *value;
Float @property float value; @property NSNumber<RLMFloat> *value;
Double @property double value; @property NSNumber<RLMDouble> *value;
String @property NSString *value; @property NSString *value;
Data @property NSData *value; @property NSData *value;
Date @property NSDate *value; @property NSDate *value;
Object n/a: 必須是可選值 @property Object *value;
List @property RLMArray<Object *><Object> *value; n/a: 必須是非可選值
LinkingObjects @property (readonly) RLMLinkingObjects<Object *> *value; n/a: 必須是非可選值
  1. Objective?C 引用類型的必需屬性必須要聲明在聯(lián)合體當(dāng)中:
@implementation MyModel
+ (NSArray *)requiredProperties {
    return @[@"value"];
}
@end
  1. 鏈接對象屬性必須連帶 +linkingObjectsProperties 方法一同聲明:
@implementation MyModel
+ (NSDictionary *)linkingObjectsProperties {
    return @{ @"property": [RLMPropertyDescriptor descriptorWithClass:Class.class propertyName:@"link"] };
}
@end

屬性特性(attributes)

注意由于 Realm 在自己的引擎內(nèi)部有很好的語義解釋系統(tǒng)睛低,所以 Objective?C 的許多屬性特性將被忽略,如 nonatomic, atomic, strong, copyweak 等服傍。 因此為了避免誤解暇昂,我們推薦您在編寫數(shù)據(jù)模型的時(shí)候不要使用任何的屬性特性。 當(dāng)然伴嗡,如果您已經(jīng)設(shè)置了這些屬性特性急波,那么在 RLMObject 對象被寫入 Realm 數(shù)據(jù)庫前,這些特性會一直生效瘪校。 無論 RLMObject 對象是否受到 Realm 管理澄暮,您為其編寫的自定義 gettersetter 方法都能正常工作。
如果您在 Swift 中使用 Objective-C 版本的 Realm 的話阱扬,模型的屬性前面需要加上 dynamic var泣懊,這是為了讓這些屬性能夠被底層數(shù)據(jù)庫數(shù)據(jù)所訪問。

索引屬性(Indexed Properties)

重寫 +indexedProperties
方法可以為數(shù)據(jù)模型中需要添加索引的屬性建立索引:

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book
+ (NSArray *)indexedProperties {
  return @[@"title"];
}
@end

Realm 支持字符串麻惶、整數(shù)馍刮、布爾值以及 NSDate 屬性作為索引。
對屬性進(jìn)行索引可以減少插入操作的性能耗費(fèi)窃蹋,加快比較檢索的速度(比如說 = 以及 IN 操作符)卡啰。

屬性默認(rèn)值

重寫+defaultPropertyValues
可以每次在對象創(chuàng)建之后為其提供默認(rèn)值静稻。

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book
+ (NSDictionary *)defaultPropertyValues {
    return @{@"price" : @0, @"title": @""};
}
@end

對象的自更新特性

RLMObject 實(shí)例是底層數(shù)據(jù)的動態(tài)表現(xiàn),其會進(jìn)行自動更新匈辱,這意味著對象不需要進(jìn)行刷新振湾。修改某個(gè)對象的屬性會立刻影響到其他所有指向同一個(gè)對象的實(shí)例。

Dog *myDog = [[Dog alloc] init];
myDog.name = @"小白";
myDog.age = 1;

[realm transactionWithBlock:^{
  [realm addObject:myDog];
}];

Dog *myPuppy = [[Dog objectsWhere:@"age == 1"] firstObject];
[realm transactionWithBlock:^{
  myPuppy.age = 2;
}];

myDog.age; // => 2

RLMObject 的這個(gè)特性不僅讓 Realm 保證速度和效率亡脸,它同時(shí)還讓代碼更加簡潔押搪、更為靈活。比如說浅碾,如果您的 UI 代碼是基于某個(gè)特定的 Realm 對象來現(xiàn)實(shí)的大州,那么在觸發(fā) UI 重繪之前,您不用擔(dān)心數(shù)據(jù)的刷新或者重新檢索等問題垂谢。
您也可以查看 Realm 通知 一節(jié)以確認(rèn) Realm 數(shù)據(jù)何時(shí)被更新摧茴,比如說由此來決定應(yīng)用 UI 何時(shí)需要被更新。此外埂陆,還可以使用 鍵值編碼苛白,當(dāng)某個(gè) RLMObject 的特定屬性發(fā)生更新時(shí)去發(fā)送通知。

主鍵(Primary Keys)

重寫 +primaryKey
可以設(shè)置模型的主鍵焚虱。聲明主鍵之后购裙,對象將允許進(jìn)行查詢,并且更新速度更加高效鹃栽,而這也會要求每個(gè)對象保持唯一性躏率。 一旦帶有主鍵的對象被添加到 Realm 之后,該對象的主鍵將不可修改民鼓。

@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end

@implementation Person
+ (NSString *)primaryKey {
    return @"id";
}
@end

忽略屬性(Ignored Properties)

重寫 +ignoredProperties
可以防止 Realm 存儲數(shù)據(jù)模型的某個(gè)屬性薇芝。Realm 將不會干涉這些屬性的常規(guī)操作,它們將由成員變量(ivar)提供支持丰嘉,并且您能夠輕易重寫它們的 settergetter夯到。

@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // 只讀屬性將被自動忽略
@property NSString *firstName;
@property NSString *lastName;
@end

@implementation Person
+ (NSArray *)ignoredProperties {
    return @[@"tmpID"];
}
- (NSString *)name {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end

忽略屬性的行為與 Objective-C 或者 Swift 類當(dāng)中的普通對象相似。它們并不支持任何一種 Realm 特定的功能饮亏。例如耍贾,無法通過查詢來檢索忽略屬性,也無法實(shí)現(xiàn)自動更新路幸,即便另一個(gè)相同對象的實(shí)例的忽略屬性值發(fā)生了變更荐开。此外忽略屬性發(fā)生更改的時(shí)候也不會觸發(fā)通知,盡管仍然可以使用 KVO 來實(shí)現(xiàn)簡直觀察简肴。

模型繼承

Realm 允許模型能夠生成更多的子類晃听,也允許跨模型進(jìn)行代碼復(fù)用,但是由于某些 Cocoa 特性使得運(yùn)行時(shí)中豐富的類多態(tài)無法使用。以下是可以完成的操作:
父類中的類方法能扒,實(shí)例方法和屬性可以被它的子類所繼承
子類中可以在方法以及函數(shù)中使用父類作為參數(shù)

以下是不能完成的:
多態(tài)類之間的轉(zhuǎn)換(例如子類轉(zhuǎn)換成子類佣渴,子類轉(zhuǎn)換成父類,父類轉(zhuǎn)換成子類等)
同時(shí)對多個(gè)類進(jìn)行檢索
多類容器 (RLMArray 以及 RLMResults)赫粥。

向 Realm 中增加此特性已經(jīng)在規(guī)劃當(dāng)中,并且我們暫時(shí)提供了一些代碼示例予借,以便能夠?qū)ΩR姷哪J竭M(jìn)行處理越平。

另外,如果您的代碼實(shí)現(xiàn)允許的話灵迫,我們建議您使用以下模式秦叛,也就是使用類組合模式來構(gòu)建子類,以便能夠包含其他類中的相關(guān)邏輯:

// 基礎(chǔ)模型
@interface Animal : RLMObject
@property NSInteger age;
@end
@implementation Animal
@end

// 包含有 Animal 的模型
@interface Duck : RLMObject
@property Animal *animal;
@property NSString *name;
@end
@implementation Duck
@end

@interface Frog : RLMObject
@property Animal *animal;
@property NSDate *dateProp;
@end
@implementation Frog
@end

// 用法
Duck *duck =  [[Duck alloc] initWithValue:@{@"animal" : @{@"age" : @(3)}, @"name" : @"Gustav" }];

集合

Realm 擁有一系列能夠幫助表示一組對象的類型瀑粥,我們稱之為「Realm 集合」:
1挣跋、RLMResults
類,表示從檢索 中所返回的對象集合狞换。
2避咆、RLMArray
類,表示模型中的對多關(guān)系修噪。
3查库、RLMLinkingObjects
類,表示模型中的反向關(guān)系黄琼。
4樊销、RLMCollection
協(xié)議,定義了所有 Realm 集合所需要遵守的常用接口脏款。

Realm 集合實(shí)現(xiàn)了 RLMCollection 協(xié)議围苫,這確保它們能夠保持一致。這個(gè)協(xié)議繼承自 NSFastEnumeration撤师,因此它應(yīng)當(dāng)與其他 Foundation 當(dāng)中的集合用法一致剂府。 其他常用的 Realm 集合 API 也在這個(gè)協(xié)議當(dāng)中進(jìn)行了聲明,例如其中包括檢索剃盾、排序以及聚合操作周循。 RLMArray 擁有額外的修改操作,這些操作不在協(xié)議接口當(dāng)中有定義万俗,例如添加和刪除對象湾笛。
使用 RLMCollection 協(xié)議,您可以編寫能夠操作任意 Realm 集合的泛型代碼:

@implementation MyObject
- (void)operateOnCollection:(id<RLMCollection>)collection {
  // collection 既可以是 RLMResults闰歪,也可以是 RLMArray
  NSLog(@"對集合 %@s 進(jìn)行操作", collection.objectClassName);
}
@end

對象存儲

對對象的所有更改(添加嚎研,修改和刪除)都必須通過寫入事務(wù)(transaction)完成。

Realm 的對象可以被實(shí)例化并且作為unmanaged對象使用(也就是還未添加到 Realm 數(shù)據(jù)庫中的對象),和其他常規(guī)Objective?C對象無異临扮。
如果您想要在多個(gè)線程中共享對象论矾,或者在應(yīng)用重啟后重復(fù)使用對象,那么您必須將其添加到 Realm 數(shù)據(jù)庫中——這個(gè)操作必須在寫入事務(wù)中完成杆勇。
因?yàn)閷懭胧聞?wù)將會產(chǎn)生不可忽略的性能消耗贪壳,因此你應(yīng)當(dāng)檢視你的代碼以確保減少寫入事務(wù)的次數(shù)。
由于寫入事務(wù)像其余硬盤讀寫操作一樣蚜退,會出現(xiàn)失敗的情況闰靴,因此 -[RLMRealm transactionWithBlock:] 以及 -[RLMRealm commitWriteTransaction] 可以選擇加上 NSError 指針參數(shù) 因此你可以處理和恢復(fù)諸如硬盤空間溢出之類的錯(cuò)誤。此外钻注,其他的錯(cuò)誤都無法進(jìn)行恢復(fù)蚂且。簡單起見,我們的代碼示例并不會處理這些錯(cuò)誤幅恋,但是您應(yīng)當(dāng)在您應(yīng)用當(dāng)中注意到這些問題杏死。

創(chuàng)建對象

當(dāng)定義完數(shù)據(jù)模型之后,您可以將您的 RLMObject 子類實(shí)例化捆交,然后向 Realm 中添加新的實(shí)例淑翼。我們以下面這個(gè)簡單的模型為例:

// 狗狗的數(shù)據(jù)模型
@interface Dog : RLMObject
@property NSString *name;
@property NSInteger age;
@end

// 實(shí)現(xiàn)文件
@implementation Dog
@end

我們可以用多種方法創(chuàng)建一個(gè)新的對象:

// (1) 創(chuàng)建一個(gè)狗狗對象,然后設(shè)置其屬性
Dog *myDog = [[Dog alloc] init];
myDog.name = @"大黃";
myDog.age = 10;

// (2) 通過字典創(chuàng)建狗狗對象
Dog *myOtherDog = [[Dog alloc] initWithValue:@{@"name" : @"豆豆", @"age" : @3}];

// (3) 通過數(shù)組創(chuàng)建狗狗對象
Dog *myThirdDog = [[Dog alloc] initWithValue:@[@"豆豆", @3]];

使用指定初始化器(designated initializer)創(chuàng)建對象是最簡單的方式品追。請注意窒舟,所有的必需屬性都必須在對象添加到 Realm 前被賦值。
通過使用恰當(dāng)?shù)逆I值诵盼,對象還可以通過字典完成創(chuàng)建惠豺。
最后,RLMObject 子類還可以通過數(shù)組完成實(shí)例化风宁,數(shù)組中的值必須和數(shù)據(jù)模型中對應(yīng)屬性的次序相同洁墙。

嵌套屬性(Nested Object)

如果某個(gè)對象中有 RLMObject 或者 RLMArray 類型的屬性,那么通過使用嵌套的數(shù)組或者字典便可以對這些屬性遞歸地進(jìn)行設(shè)置戒财。您只需要簡單的用表示其屬性的字典或者數(shù)組替換每個(gè)對象即可:

// 這里我們就可以使用已存在的狗狗對象來完成初始化
Person *person1 = [[Person alloc] initWithValue:@[@"李四", @30, @[aDog, anotherDog]]];

// 還可以使用多重嵌套
Person *person2 = [[Person alloc] initWithValue:@[@"李四", @30, @[@[@"小黑", @5],
                                                                 @[@"旺財(cái)", @6]]]];

即使是數(shù)組以及字典的多重嵌套热监,Realm 也能夠輕松完成對象的創(chuàng)建。注意 RLMArray 只能夠包含 RLMObject 類型饮寞,不能包含諸如 NSString
之類的基礎(chǔ)類型孝扛。

添加數(shù)據(jù)

向 Realm 中添加數(shù)據(jù)的步驟如下:

// 創(chuàng)建對象
Person *author = [[Person alloc] init];
author.name    = @"大衛(wèi)·福斯特·華萊士";

// 獲取默認(rèn)的 Realm 實(shí)例
RLMRealm *realm = [RLMRealm defaultRealm];
// 每個(gè)線程只需要使用一次即可

// 通過事務(wù)將數(shù)據(jù)添加到 Realm 中
[realm beginWriteTransaction];
[realm addObject:author];
[realm commitWriteTransaction];

等您將某個(gè)對象添加到 Realm 數(shù)據(jù)庫之后,您可以繼續(xù)使用它幽崩,并且您對其做的任何更改都會被保存(必須在一個(gè)寫入事務(wù)當(dāng)中完成)苦始。當(dāng)寫入事務(wù)提交之后,使用相同 Realm 數(shù)據(jù)源的其他線程才能夠?qū)@個(gè)對象進(jìn)行更改慌申。

請注意:如果在進(jìn)程中存在多個(gè)寫入操作的話陌选,那么單個(gè)寫入操作將會阻塞其余的寫入操作,并且還會鎖定該操作所在的當(dāng)前線程。
這個(gè)特性與其他持久化解決方案類似咨油,我們建議您使用該方案常規(guī)的最佳做法:將寫入操作轉(zhuǎn)移到一個(gè)獨(dú)立的線程中執(zhí)行您炉。

由于 Realm 采用了 MVCC 設(shè)計(jì)架構(gòu),讀取操作 并不會 因?yàn)閷懭胧聞?wù)正在進(jìn)行而受到影響役电。除非您需要立即使用多個(gè)線程來同時(shí)執(zhí)行寫入操作赚爵,不然您應(yīng)當(dāng)采用批量化的寫入事務(wù),而不是采用多次少量的寫入事務(wù)法瑟。
查看RLMRealmRLMObject來獲得更多內(nèi)容冀膝。

更新數(shù)據(jù)

Realm 提供了一系列用以更新數(shù)據(jù)的方式,這些方式都有著各自所適應(yīng)的情景瓢谢。請選擇最符合您當(dāng)前需求的方式來使用:

內(nèi)容直接更新

您可以在寫入事務(wù)中通過設(shè)置某個(gè)對象的屬性從而完成對象的更新操作畸写。

// 在一個(gè)事務(wù)中更新對象
[realm beginWriteTransaction];
author.name = @"托馬斯·品欽";
[realm commitWriteTransaction];

通過主鍵更新

如果您的數(shù)據(jù)模型中設(shè)置了主鍵的話驮瞧,那么您可以使用+[RLMObject createOrUpdateInRealm:withValue:]
來更新對象氓扛,或者當(dāng)對象不存在時(shí)插入新的對象。

// 創(chuàng)建一個(gè)帶有主鍵的“書籍”對象论笔,作為事先存儲的書籍
Book *cheeseBook = [[Book alloc] init];
cheeseBook.title = @"奶酪食譜";
cheeseBook.price = @9000;
cheeseBook.id = @1;

// 通過 id = 1 更新該書籍
[realm beginWriteTransaction];
[Book createOrUpdateInRealm:realm withValue:cheeseBook];
[realm commitWriteTransaction];

如果主鍵 id 為1的 Book 對象已經(jīng)存在于數(shù)據(jù)庫當(dāng)中了采郎,那么對象就會簡單地進(jìn)行更新。而如果不在數(shù)據(jù)庫中存在的話狂魔,那么這個(gè)操作將會創(chuàng)建一個(gè)新的 Book 對象并添加到數(shù)據(jù)庫當(dāng)中蒜埋。
您同時(shí)通過傳遞您想要更新值的集合,從而更新帶有主鍵的某個(gè)對象的部分值最楷,比如說如下所示:

// 假設(shè)帶有主鍵值 `1` 的“書籍”對象已經(jīng)存在
[realm beginWriteTransaction];
[Book createOrUpdateInRealm:realm withValue:@{@"id": @1, @"price": @9000.0f}];
// 這本書的`title`屬性不會被改變
[realm commitWriteTransaction];

如果對象沒有定義主鍵的話整份,那么您不能夠調(diào)用出現(xiàn)在本章的這些方法(也就是那些以 OrUpdate 結(jié)尾的方法)。
請注意:當(dāng)對象更新的時(shí)候籽孙,NSNull 仍然會被認(rèn)為是可選屬性 的有效值烈评。如果您提供了一個(gè)屬性值為 NSNull 的字典,那么這些都會應(yīng)用到您的對象當(dāng)中犯建,并且對應(yīng)的屬性都將為空讲冠。為了確保不出現(xiàn)任何意外的數(shù)據(jù)丟失,請?jiān)谑褂么朔椒ǖ臅r(shí)候再三確認(rèn)只提供了您想要進(jìn)行更新的屬性适瓦。

鍵值編碼

RLMObject竿开、RLMResult 以及 RLMArray 都遵守鍵值編碼(Key-Value Coding)(KVC)機(jī)制。 當(dāng)您在運(yùn)行時(shí)才能決定哪個(gè)屬性需要更新的時(shí)候玻熙,這個(gè)方法是最有用的否彩。
將 KVC 應(yīng)用在集合當(dāng)中是大量更新對象的極佳方式,這樣就可以不用經(jīng)常遍歷集合嗦随,為每個(gè)項(xiàng)目創(chuàng)建一個(gè)訪問器了胳搞。

RLMResults<Person *> *persons = [Person allObjects];
[[RLMRealm defaultRealm] transactionWithBlock:^{
  [[persons firstObject] setValue:@YES forKeyPath:@"isFirst"];
  // 將每個(gè)人的 planet 屬性設(shè)置為“地球”
  [persons setValue:@"地球" forKeyPath:@"planet"];
}];

刪除數(shù)據(jù)

通過在寫入事務(wù)中將要?jiǎng)h除的對象傳遞給 -[RLMRealm deleteObject:]
方法,即可完成刪除操作。

// 存儲在 Realm 中的 cheeseBook 對象

// 在事務(wù)中刪除一個(gè)對象
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];

您也能夠刪除存儲在 Realm 中的所有數(shù)據(jù)肌毅。注意筷转,Realm 文件的大小不會被改變,因?yàn)樗鼤A艨臻g以供日后快速存儲數(shù)據(jù)悬而。

// 從 Realm 中刪除所有數(shù)據(jù)
[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呜舒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子笨奠,更是在濱河造成了極大的恐慌袭蝗,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件般婆,死亡現(xiàn)場離奇詭異到腥,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蔚袍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門乡范,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啤咽,你說我怎么就攤上這事晋辆。” “怎么了宇整?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵瓶佳,是天一觀的道長。 經(jīng)常有香客問我鳞青,道長霸饲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任臂拓,我火速辦了婚禮厚脉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埃儿。我一直安慰自己器仗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布童番。 她就那樣靜靜地躺著精钮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剃斧。 梳的紋絲不亂的頭發(fā)上轨香,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機(jī)與錄音幼东,去河邊找鬼臂容。 笑死科雳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脓杉。 我是一名探鬼主播糟秘,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼球散!你這毒婦竟也來了尿赚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蕉堰,失蹤者是張志新(化名)和其女友劉穎凌净,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屋讶,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冰寻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了皿渗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斩芭。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖羹奉,靈堂內(nèi)的尸體忽然破棺而出秒旋,到底是詐尸還是另有隱情约计,我是刑警寧澤诀拭,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站煤蚌,受9級特大地震影響耕挨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尉桩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一筒占、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜘犁,春花似錦翰苫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至屈扎,卻和暖如春埃唯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹰晨。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工墨叛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留止毕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓漠趁,卻偏偏與公主長得像扁凛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子闯传,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

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