Realm Objective‑C 2.4.3 官方文件的翻譯
開始
Realm Objective-C使能夠以安全,持久和快速的方式有效地編寫應用程式的模型層,例子如下:
// Define your models like regular Objective‑C classes
@interface Dog : RLMObject
@property NSString *name;
@property NSData *picture;
@property NSInteger age;
@end
@implementation Dog
@end
RLM_ARRAY_TYPE(Dog)
@interface Person : RLMObject
@property NSString *name;
@property RLMArray<Dog *><Dog> *dogs;
@end
@implementation Person
@end
// Use them like regular Objective‑C objects
Dog *mydog = [[Dog alloc] init];
mydog.name = @"Rex";
mydog.age = 1;
mydog.picture = nil; // properties are nullable
NSLog(@"Name of dog: %@", mydog.name );
// Query Realm for all dogs less than 2 years old
RLMResults<Dog *> *puppies = [Dog objectsWhere:@"age < 2"];
puppies.count; // => 0 because no dogs have been added to the Realm yet
// Persist your data easily
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:mydog];
}];
// Queries are updated in realtime
puppies.count; // => 1
// Query and update the result in another thread
dispatch_async(dispatch_queue_create("background", 0), ^{
Dog *theDog = [[Dog objectsWhere:@"age == 1"] firstObject];
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
theDog.age = 3;
[realm commitWriteTransaction];
});
If you have an app that is presently using Core Data and have been considering switching to Realm, we recently published an article discussing how to go about doing this. Go check it out!
如果你打算使用realm替換Core Data,我們(官方)最近將出一片文章講述如何替換。
環境要求
- iOS7 or later,macOS 10.9 或者以後版本,tvOS 和watchOS的所有版本。
- 要求Xcode 8.0及其以後版本。支援Swift2.x和Xcode 7.3最後一個版本是Realm OC 2.3.0
安裝
以OC及frameworks的情況說明
1. 下載最新的release版本的Realm 並且解壓
2. 在Xcode工程中找到“General”設定項,把Realm.framework 從 ios/dynamic/目錄中拖到“Embedded Binaries”選項中,確保在拖拽過程中選中“Copy items if needed ”(如果在多平臺中使用realm時除外),點選“Finish”就可以了
匯入Realm Framework
在OC原始檔的最頂部,使用#import <Realm/Realm.h>
匯入Realm OC 然後便可以使用Realm的相關特性
RLMArray
屬性
在OC中我們依賴協議一致性使Realm知道RLMArray一對多的關係中包含的物件的型別。在Swift中是不可能的,你可以使用以下語法代替:
class Person: RLMObject {
dynamic var dogs = RLMArray(objectClassName: Dog.className())
}
其結果等同於
@interface Person : RLMObject
@property RLMArray<Dog *><Dog> *dogs;
@end
Realm Browser
官方提供一個獨立的Mac app來檢視和編輯realm databases
你可以使用選單項*Tools > Generate demo database,用一些簡單的資料生成一個測試的資料庫。
如果在尋找app中尋找Realm file,你可以參閱StackOverflow answer 這篇文章。你可以在appstore中下載到該應用。
Xcode Plugin
官方提供的Xcode外掛可以很容易的生成新的Realm物件。
通過Alcatraz 找到“RealmPlugin”去安裝Realm plugin外掛。
你也可以通過開啟[release.zip]中的(https://static.realm.io/downloads/objc/realm-objc-2.4.3.zip)plugin/RealmPlugin.xcodeproj
手動的去新增,並且點選build,你需要關閉和重啟Xcode。
例子
你可以在官方釋出的release.zip 中的examples /下找到iOS和OS X的示例應用程式,演示如何使用Realm的許多功能,如遷移,如何使用UITableViewControllers,加密,命令列工具等
Models
Realm 資料模型使用普通的帶屬性的類來定義。簡單的繼承RLMObject
物件或者現有的模型去建立Realm data模型物件。Realm和其他的OC物件一樣,你可以新增屬性和協議並使用它們。主要的限制是你只能在建立它的執行緒上使用一個物件,你不能直接訪問它的任何持久化屬性的ivar。
如果你已經安裝了官方的Xcode外掛,將會有一個很好的模板,在RLMArray
對話方塊中建立介面和實現檔案。
關係和巢狀的資料結構和模型可以簡單的通過目標型別的屬性或物件的型別列表的RLMArrays簡單建模
#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 *><Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // define RLMArray<Person>
// Implementations
@implementation Dog
@end // none needed
@implementation Person
@end // none needed
See RLMObject for more details.
Supported Types
Realm支援以下屬性型別:BOOL
,bool
,int
,NSInteger
,long
,long long
,float
,double
,NSString
,NSDate
,NSData
和用特定型別標記的NSNumber
。
不建議使用CGFloat
屬性,因為型別不是平臺獨立的。
可以使用RLMArray <Object *> <Object>
和RLMObject
子類來建模關係,例如to-many和to-one。
RLMArrays
支援編譯時Objective-C泛型(如果可用)(Xcode 7或更高版本)。下面是屬性定義的不同元件的含義,以及它們為什麼有用:
RLMArray
:屬性型別.<Object *>
:泛型特化.這有助於防止在編譯時使用錯誤物件型別的陣列.<Object>
:RLMArray
遵循的協議。這使得Realm知道如何在執行時專門化此模型的模式
Relationships
RLMObject
可以通過使用RLMObject
和RLMArray
屬性彼此連結。 RLMArray
具有非常類似於NSArray
的介面,並且可以使用索引下標來訪問包含在RLMArray
中的物件。與NSArrays
不同,RLMArrays
是型別化的,並且只儲存單個子類型別的RLMObject
。有關更多詳細資訊,請參閱RLMArray。
假設你的Person類已經定義(見上文),讓我們建立另一個類Dog:
// Dog.h
@interface Dog : RLMObject
@property NSString *name;
@end
To-One Relationships
對於多對一或一對一關係,只需使用RLMObject子類的型別宣告一個屬性:
// Dog.h
@interface Dog : RLMObject
// ... other property declarations
@property Person *owner;
@end
你可以像使用任何其他屬性一樣使用此屬性:
Person *jim = [[Person alloc] init];
Dog *rex = [[Dog alloc] init];
rex.owner = jim;
使用RLMObject
屬性時,可以使用正常屬性語法訪問巢狀屬性。例如rex.owner?.address.country
將遍歷物件圖並根據需要自動從Realm中獲取每個物件。
To-Many Relationships
你可以使用RLMArray
屬性定義一對多關係。 RLMArrays包含單個型別的其他RLMObject
,並且具有非常類似於NSMutableArray
的介面。
RLMArray
可能包含對同一個Realm物件的多個引用,包括具有主鍵的物件。例如,你可以建立一個空的RLMArray
並將相同的物件插入它三次;如果訪問索引0,1和2中的任一個處的元素,則RLMArray
將返回該物件。
要在連結到多個dog的Person模型上新增“dogs”屬性,我們必須首先定義一個RLMArray <Dog>
型別。這通過在相應模型介面底部的巨集來完成:
// Dog.h
@interface Dog : RLMObject
// ... property declarations
@end
RLM_ARRAY_TYPE(Dog) // Defines an RLMArray<Dog> type
RLM_ARRAY_TYPE
巨集建立一個協議,以使用RLMArray <Dog>
語法。如果巨集未放置在模型介面的底部,則可能必須前置宣告模型類。
然後可以宣告RLMArray <Dog>
型別的屬性:
// Person.h
@interface Person : RLMObject
// ... other property declarations
@property RLMArray<Dog *><Dog> *dogs;
@end
你可以照常訪問和賦值RLMArray屬性
// Jim is owner of Rex and all dogs named "Fido"
RLMResults<Dog *> *someDogs = [Dog objectsWhere:@"name contains 'Fido'"];
[jim.dogs addObjects:someDogs];
[jim.dogs addObject:rex];
請注意,雖然可以為RLMArray屬性指定nil,但這隻能“清空”陣列,而不是刪除陣列。這意味著可以始終將物件新增到RLMArray屬性,即使將其設定為nil。
RLMArray屬性保證保留它們的插入順序。
Inverse Relationships
連結是單向的。因此,如果一個to-many屬性Person.dogs
連結到一個Dog
例項,並且一個屬性Dog.owner
連結到Person
,這些連結是彼此獨立的。將Dog
附加到Person
例項的dogs
屬性不會自動將dog
的owner
屬性設定為此Person
。因為手動同步的關係對容易出錯,複雜和重複資訊,Realm提供連結物件屬性來表示這些逆關係。
使用連結物件屬性,你可以從特定屬性獲取連結到給定物件的所有物件。例如,Dog
物件可以具有名為owner
的屬性,其中包含在其dogs
屬性中具有此確切Dog
物件的所有Person
物件。這通過使屬性型別為RLMLinkingObjects
,然後覆蓋+ [RLMObject linkingObjectsProperties]
來指示所有者與Person
模型物件的關係來實現。(太TM的繞了,搞了半個小時才弄清楚)
@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 *
屬性允許將它們設定為nil。如果要求一個值存在,可以覆蓋RLMObject
子類上的+ requiredProperties
方法。例如,使用以下模型定義,嘗試將人員的名稱設定為nil
將丟擲異常,但允許將其生日設定為nil
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end
@implementation Person
+ (NSArray *)requiredProperties {
return @[@"name"];
}
@end
使用NSNumber *
屬性儲存可選數字。因為Realm對不同型別的數字使用不同的儲存格式,所以必須使用RLMInt
,RLMFloat
,RLMDouble
或RLMBool
之一來標記該屬性。分配給該屬性的所有值都將轉換為指定的型別。
請注意,NSDecimalNumber
值只能分配給RLMDouble
Realm屬性,Realm將儲存該值的雙精度浮點近似值,而不是底層十進位制值。
例如,如果我們想要儲存該人的年齡而不是他們的生日,而當你不知道該人的年齡時仍然允許nil
:
@interface Person : RLMObject
@property NSString *name;
@property NSNumber<RLMInt> *age;
@end
@implementation Person
+ (NSArray *)requiredProperties {
return @[@"name"];
}
@end
RLMObject
子類屬性總是可以為nil
,因此不能包含在requiredProperties
中,而RLMArray
不支援儲存nil
Cheatsheet
此表提供了宣告模型屬性的方便參考。
Type | Non-optional | Optional |
---|---|---|
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 String *value; |
@property NSString *value; |
Data | @property NSData *value; |
@property NSData *value; |
Date | @property NSDate *value; |
@property NSDate *value; |
Object | n/a: must be optional | @property Object *value; |
List | @property RLMArray<Object *><Object> *value; |
n/a: must be non-optional |
LinkingObjects | @property (readonly) RLMLinkingObjects<Object *> *value; |
n/a: must be non-optional |
1)Objective-C引用型別的必需屬性必須與以下語句結合宣告:
@implementation MyModel
+ (NSArray *)requiredProperties {
return @[@"value"];
}
@end
2)連結物件屬性必須與+ linkingObjectsProperties方法組合宣告
@implementation MyModel
+ (NSDictionary *)linkingObjectsProperties {
return @{ @"property": [RLMPropertyDescriptor descriptorWithClass:Class.class propertyName:@"link"] };
}
@end
Property Attributes
注意,Realm忽略ObjectiveC屬性修飾符,如非原子,原子,強,複製,弱等等。這是因為Realm有自己的優化儲存語義。所以為了避免誤導,我們建議編寫沒有任何屬性修飾符的模型。但是,如果設定屬性修飾符,它們將一直使用,直到將RLMObject新增到Realm(潛臺詞就是一旦新增到Realm這些修飾符就不一定好用了)。 getter和setter的自定義名稱正常工作,而不管RLMObject是否由Realm管理。如果使用Realm Objective-C和Swift,模型屬性需要動態var屬性,以便這些屬性成為底層資料庫資料的訪問器。(其實就是告訴不要新增任何屬性修飾符)
Indexed Properties
覆蓋+ indexedProperties以設定模型中應該索引哪些屬性:
@interface Book : RLMObject
@property float price;
@property NSString *title;
@end
@implementation Book
+ (NSArray *)indexedProperties {
return @[@"title"];
}
@end
Realm支援對字串,整數,布林和NSDate屬性的索引。
索引屬性將大大加快查詢的速度,其中的屬性被比較相等(即=和IN運算子),代價是較慢的插入
Default Property Values
重寫 + defaultPropertyValues
在每次建立物件時提供預設值
@interface Book : RLMObject
@property float price;
@property NSString *title;
@end
@implementation Book
+ (NSDictionary *)defaultPropertyValues {
return @{@"price" : @0, @"title": @""};
}
@end
Auto-Updating Objects
RLMObject例項是實時的,自動更新檢視到底層資料,這意味著物件不必被重新整理。修改物件的屬性將立即反映在引用同一物件的任何其他例項中
Dog *myDog = [[Dog alloc] init];
myDog.name = @"Fido";
myDog.age = 1;
[realm transactionWithBlock:^{
[realm addObject:myDog];
}];
Dog *myPuppy = [[Dog objectsWhere:@"age == 1"] firstObject];
[realm transactionWithBlock:^{
myPuppy.age = 2;
}];
myDog.age; // => 2
RLMObject的這個方面不僅保持Realm的快速和高效,它允許你的程式碼更簡單和更多的反應。例如,如果的UI程式碼依賴於特定的Realm物件,則不需要擔心在觸發UI重繪之前重新整理或重新獲取它。(潛臺詞就是realm可以快到UI渲染之前肯定能夠返回給你資料,作死的不算)
可以訂閱Realm通知,以瞭解物件中的Realm資料何時更新,指示應用程式的UI應該何時重新整理。或者,可以使用鍵值觀察在更新RLMObject的特定屬性時通知。
Primary Keys
重寫+ primaryKey
以設定模型的主鍵。宣告主鍵允許有效地查詢和更新物件,並強制實現每個值的唯一性。將帶有主鍵的物件新增到域後,無法更改主鍵
@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end
@implementation Person
+ (NSString *)primaryKey {
return @"id";
}
@end
Ignored Properties
重寫+ ignoredProperties
以防止Realm持久化模型屬性。 Realm不會干擾這些屬性的正常操作:它們將由ivars支援,並且可以自由覆蓋其setter和getter。
@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // read-only properties are automatically ignored
@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類的正常屬性完全相同。它們不支援任何Realm特定的功能。例如,它們不能在查詢中使用,如果表示相同Realm物件的另一個例項上的相同屬性發生更改,則它們不會自動更新它們的值,並且它們在更改時不會觸發通知。然而,他們仍然可以使用KVO觀察。
Model Inheritance
Realm允許模型進一步子類化,允許在模型之間進行大量程式碼重用,但是一些Cocoa特性對執行時豐富的類多型性有所幫助(潛臺詞儘量簡單的使用realm的物件)。以下是可能的:
- 父類上的類方法,例項方法和屬性在其子類中繼承。
- 將父類作為引數的方法和函式可以對子類進行操作。
以下是不可能的:
- 在多型類之間轉換(即,子類到子類,子類到父類,父類到子類,等等)。
- 同時查詢多個類。
- 多類容器(RLMArray和RLMResults)。
我們建議使用以下模式的類組合構建包含其他類的邏輯的子類:
// Base Model
@interface Animal : RLMObject
@property NSInteger age;
@end
@implementation Animal
@end
// Models composed with 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
// Usage
Duck *duck = [[Duck alloc] initWithValue:@{@"animal" : @{@"age" : @(3)}, @"name" : @"Gustav" }];
Collections
Realm有幾種型別可以幫助表示物件組,我們稱之為“Realm集合”
RLMResults
一個表示查詢返回物件的集合類。RLMArray
一個在模型中表示一對多關係集合類。RLMLinkingObjects
一個表示反向指向關係集合類RLMCollection
一個定義所realm Collections遵循的公共介面協議的類。
Realm集合符合RLMCollection協議,確保它們的行為一致。此協議從NSFastEnumeration
繼承,以便它可以以與其他Foundation
集合相同的方式使用。在此協議中聲明瞭其他公共Realm集合API,例如查詢,排序和聚合操作等。 RLMArrays
具有擴充套件超出協議介面的額外的新增操作,例如新增和刪除物件。
使用RLMCollection
協議,你可以編寫可以在任何Realm集合上操作的通用程式碼
@implementation MyObject
- (void)operateOnCollection:(id<RLMCollection>)collection {
// Collection could be either RLMResults or RLMArray
NSLog(@"operating on collection of %@s", collection.objectClassName);
}
@end
Writes
對物件的所有更改(新增,修改和刪除)必須在寫事務中完成。
Realm物件可以被例項化,並像常規Objective-C物件一樣用作非託管物件(即尚未新增到Realm)。要線上程之間共享物件或在應用啟動之間重新使用它們,必須將它們新增到同一個Realm中,這是必須在寫事務中完成的操作。
由於寫事務會產生不可忽略的開銷,因此你應該構建的程式碼以最小化寫事務的數量。(儘量少些事務)
因為寫事務可能像任何其他磁碟IO操作一樣失敗,兩個 - [RLMRealm transactionWithBlock:]& - [RLMRealm commitWriteTransaction]
可選地採用NSError指標引數,因此你可以處理並從諸如磁碟空間不足的故障中恢復。沒有其他可恢復的錯誤。為簡潔起見,我們的程式碼示例不處理這些錯誤,由使用中在自己的app裡處理。
Creating Objects
定義模型後,可以例項化RLMObject子類,並將新例項新增到Realm。參考這個簡單的模型:
// Dog model
@interface Dog : RLMObject
@property NSString *name;
@property NSInteger age;
@end
// Implementation
@implementation Dog
@end
我們可以通過幾種方式建立新物件:
// (1) Create a Dog object and then set its properties
Dog *myDog = [[Dog alloc] init];
myDog.name = @"Rex";
myDog.age = 10;
// (2) Create a Dog object from a dictionary
Dog *myOtherDog = [[Dog alloc] initWithValue:@{@"name" : @"Pluto", @"age" : @3}];
// (3) Create a Dog object from an array
Dog *myThirdDog = [[Dog alloc] initWithValue:@[@"Pluto", @3]];
- 最明顯的是使用指定的初始化程式來建立一個物件。請注意,必須先設定所有必需的屬性,然後才能將物件新增到Realm。
- 還可以使用適當的鍵和值從字典建立物件。
- 最後,可以使用陣列例項化
RLMObject
子類。陣列中的值必須與模型中相應的屬性具有相同的順序。
Nested Objects
如果物件的屬性為RLMObjects
或RLMArrays
,則可以使用巢狀陣列和/或字典遞迴設定這些屬性。只需用表示其屬性的字典或陣列替換每個物件.
// Instead of using already existing dogs...
Person *person1 = [[Person alloc] initWithValue:@[@"Jane", @30, @[aDog, anotherDog]]];
// ...we can create them inline
Person *person2 = [[Person alloc] initWithValue:@[@"Jane", @30, @[@[@"Buster", @5],
@[@"Buddy", @6]]]];
這將適用於巢狀陣列和字典的任何組合。請注意,RLMArray
只能包含RLMObject
,而不是基本型別,如NSString
Adding Objects
如下
// Create object
Person *author = [[Person alloc] init];
author.name = @"David Foster Wallace";
// Get the default Realm
RLMRealm *realm = [RLMRealm defaultRealm];
// You only need to do this once (per thread)
// Add to Realm with transaction
[realm beginWriteTransaction];
[realm addObject:author];
[realm commitWriteTransaction];
在將物件新增到Realm之後,可以繼續使用它,並且對它所做的所有更改都將保留(並且必須在寫事務中完成)。任何更改都可用於提交寫入事務時使用相同Realm的其他執行緒。
請注意,寫操作會相互阻塞,如果正在進行多個寫操作,它將阻塞它們的執行緒。這與其他永續性解決方案類似,我們建議對此情況使用通常的最佳做法:將寫入操作歸到單獨的執行緒。
感謝Realm的MVCC架構,在寫事務開啟時,讀取不會被阻塞。除非需要同時從多個執行緒同時寫入,否則應該傾向於更大的寫事務,這些事務在許多細粒度的寫事務上做更多的工作。當將寫事務提交到Realm時,該Realm的所有其他例項將被通知並自動更新。
有關更多詳細資訊,請參閱RLMRealm
和RLMObject
。
Updating Objects
Realm提供了幾種更新物件的方法,所有這些方法都根據情況提供不同的權衡。選擇最適合的情況:
Typed Updates
// Update an object with a transaction
[realm beginWriteTransaction];
author.name = @"Thomas Pynchon";
[realm commitWriteTransaction];
Creating and Updating Objects With Primary Keys
如果模型類包含主鍵,則可以使用 - [RLMRealm addOrUpdateObject:]
,讓Realm根據主鍵值智慧地更新或新增物件。
如果具有主鍵值為“1”的Book物件已經存在於資料庫中,則該物件將被簡單地更新。如果它不存在,那麼將建立一個全新的Book物件並將其新增到資料庫。
還可以通過只傳遞要更新的值的一部分以及主鍵來部分更新具有主鍵的物件:
// Assuming a "Book" with a primary key of `1` already exists.
[realm beginWriteTransaction];
[Book createOrUpdateInRealm:realm withValue:@{@"id": @1, @"price": @9000.0f}];
// the book's `title` property will remain unchanged.
[realm commitWriteTransaction];
在未定義主鍵的物件上不能呼叫本章中顯示的方法(以OrUpdate結束)。
請注意,在更新物件時,NSNull仍被視為可選屬性的有效值。如果提供具有NSNull屬性值的字典,那麼這些將應用於物件,這些屬性將被清空。為確保不會遇到任何意外的資料丟失,請務必在使用此方法時僅提供要更新的屬性。(潛臺詞自己作死造成的問題我們不負責)
Key-Value Coding
RLMObject,RLMResult
和RLMArray
都符合鍵值編碼(KVC)。當需要確定在執行時更新哪個屬性時,這可能很有用。
將KVC應用於集合是一種大量更新物件的好方法,無需在為每個專案建立訪問器的情況下迭代集合的開銷。
RLMResults<Person *> *persons = [Person allObjects];
[[RLMRealm defaultRealm] transactionWithBlock:^{
[[persons firstObject] setValue:@YES forKeyPath:@"isFirst"];
// set each person's planet property to "Earth"
[persons setValue:@"Earth" forKeyPath:@"planet"];
}];
Deleting Objects
將要刪除的物件傳遞給寫事務中的 - [RLMRealm deleteObject:]
方法
// cheeseBook stored in Realm
// Delete an object with a transaction
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];
還可以刪除儲存在Realm中的所有物件。請注意,Realm檔案將保持其在磁碟上的大小,以便有效地將該空間用於未來的物件.
// Delete all objects from the realm
[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];
Queries
查詢返回一個RLMResults
例項,它包含一個RLMObjects
集合。 RLMResults
具有非常類似於NSArray
的介面,並且可以使用索引下標訪問包含在RLMResults
中的物件。與NSArrays
不同,RLMResults
是型別化的,並且只保留單個子類型別的RLMObject
。
所有查詢(包括查詢和屬性訪問)在Realm中都是延遲的。僅當訪問屬性時才讀取資料。
查詢的結果不是資料的副本:修改查詢的結果(在寫事務中)將直接修改磁碟上的資料。類似地,可以直接從RLMResults
中包含的RLMObjects
遍歷關係圖。
執行查詢被延遲,直到結果被使用。這意味著連結幾個臨時RLMResults
以排序和過濾的資料不會執行處理中間狀態的額外工作。
一旦執行了查詢或添加了通知塊,RLMResults
將保持與Realm中所做的更改一致,並在可能的情況下在後臺執行緒上執行查詢。
用於從Realm檢索物件的最基本的方法是+ [RLMObject allObjects]
,它返回從預設領域查詢的子型別的所有RLMObject
例項的RLMResults
。
RLMResults<Dog *> *dogs = [Dog allObjects]; // retrieves all Dogs from the default Realm
Filtering
如果你熟悉NSPredicate
,那麼你已經知道如何在Realm中查詢。 RLMObjects
,RLMRealm
,RLMArray
和RLMResults
都提供了允許通過簡單地傳遞NSPredicate
例項,謂詞字串或謂詞格式字串來查詢特定RLMObject
例項的方法,就像查詢NSArray
時一樣。
例如,以下將通過呼叫[RLMObject objectsWhere:]
來擴充套件我們前面的示例,以檢索默Realm中以“B”開頭的color為tan的dog。
// Query using a predicate string
RLMResults<Dog *> *tanDogs = [Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"];
// Query using an NSPredicate
NSPredicate *pred = [NSPredicate predicateWithFormat:@"color = %@ AND name BEGINSWITH %@",
@"tan", @"B"];
tanDogs = [Dog objectsWithPredicate:pred];
有關構建謂詞和使用我們的NSPredicate Cheatsheet的更多資訊,請參閱Apple’s Predicates程式設計指南。Realm支援許多常見謂詞:
- 比較運算元可以是屬性名稱或常量。至少有一個運算元必須是屬性名稱
- 支援int,long,long long,float,double和NSDate屬性型別的比較運算子==,<=,<,> =,>,!=和BETWEEN。如age == 45
- 身份比較==,!=,例如[Employee objectsWhere:@“company ==%@”,company]
- 比較運算子==和!=支援布林屬性
- 對於NSString和NSData屬性,我們支援==,!=,BEGINSWITH,CONTAINS和ENDSWITH運算子,例如name CONTAINS’Ja’
- 對於NSString屬性,LIKE運算子可以用於比較左手屬性和右手錶達式:?和作為萬用字元,其中?匹配1個字元,匹配0個或多個字元。例如值LIKE’?bc *’匹配字串,如“abcde”和“cbc”
- 字串的不區分大小寫的比較,例如名稱CONTAINS [c]’Ja’。注意,只有字元“A-Z”和“a-z”將被忽略
- Realm支援以下複合運算子:“AND”,“OR”和“NOT”。例如名稱BEGINSWITH’J’AND age> = 32
- 包含運算元IN,例如名稱IN {‘Lisa’,’Spike’,’Hachi’}
- Nil比較==,!=,例如
[Company objectsWhere:@"ceo == nil"]
。請注意,Realm將nil視為一個特殊值,而不是沒有值,因此與SQL nil不同的是它本身。 - any比較,例如ANY student.age <21
- 在
RLMArray
和RLMResults
屬性上支援聚合表示式@count,@min,@ max,@ sum和@avg。[Company objectsWhere:@"[email protected] > 5"]
找到所有擁有超過五名員工的公司
-支援子查詢具有以下限制:
@count
是唯一可以應用於SUBQUERY
表示式的運算子。- 必須將
SUBQUERY(...)[email protected] count
表示式與常量進行比較。 - 尚不支援相關子查詢。
有關更多資訊,請參閱[RLMObject objectsWhere:]
。
Sorting
RLMResults
允許基於key路徑,屬性或一個或多個排序描述符指定排序條件和順序。例如,以下呼叫按照名稱按字母順序對從上面的示例返回的dog進行排序:
// Sort tan dogs with names starting with "B" by name
RLMResults<Dog *> *sortedDogs = [[Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"]
sortedResultsUsingKeyPath:@"name" ascending:YES];
key路徑也可以是一對一關係的屬性
RLMResults<Person *> *dogOwners = [Person allObjects];
RLMResults<Person *> *ownersByDogAge = [dogOwners sortedResultsUsingKeyPath:@"dog.age" ascending:YES];
注意,sortedResultsUsingKeyPath:
和sortedResultsUsingProperty:
不支援多個屬性作為排序條件,並且不能連結(只有最後一次呼叫sortedResults ...
將被使用)。要按多個屬性排序,請使用sortedResultsUsingDescriptors:
與多個RLMSortDescriptor
物件。
更多參考
請注意,結果的順序只能保證在查詢排序時保持一致。出於效能原因,不保證保留插入順序。如果你需要保持插入的順序,在這裡提出一些解決方案。
Chaining
Realm的查詢引擎的一個獨特屬性是連結查詢的能力,與傳統的資料庫相比,只需要為每個連續的查詢單獨訪問資料庫伺服器,只需很少的事務性開銷。
例如,如果我們想要的結果集只是棕褐色的狗和棕褐色的狗的名字也以’B’開頭,你可能連結兩個查詢,像這樣:
這裡寫連結內容
Auto-Updating Results
RLMResults
例項是實時的,自動更新檢視到底層資料,這意味著結果從來不必重新獲取。它們總是在當前執行緒上反映Realm的當前狀態,包括在當前執行緒上的寫事務期間。一個例外是當在列舉中使用for... in
時,在列舉開始時,它將始終列舉匹配查詢的物件,即使它們中的一些被刪除或修改為在列舉期間被過濾器排除。
RLMResults<Dog *> *puppies = [Dog objectsInRealm:realm where:@"age < 2"];
puppies.count; // => 0
[realm transactionWithBlock:^{
[Dog createInRealm:realm withValue:@{@"name": @"Fido", @"age": @1}];
}];
puppies.count; // => 1
這適用於所有RLMResults
:所有物件,過濾和連結。
RLMResults
的這個屬性不僅保持Realm的快速和高效,它允許你的程式碼更簡單和更多的反應。例如,如果的檢視控制器依賴於查詢的結果,可以將RLMResults
儲存在屬性中並進行訪問,而無需在每次訪問之前確保重新整理其資料。
可以訂閱Realm通知,以瞭解何時更新Realm資料,指示的應用程式的UI應該何時重新整理,而無需重新獲取RLMResults
。
由於結果是自動更新,重要的是不要依賴於索引和計數保持不變。唯一一個RLMResults
被凍結的時候是快速列舉它.
或者,使用鍵值編碼對RLMResults
執行操作
大多數其他資料庫技術提供了從查詢中分頁結果的功能(例如SQLite中的“LIMIT”關鍵字)。這通常是為了避免從磁碟讀取過多,或者將太多的結果一次性拉到記憶體中。
由於Realm中的查詢是延遲的,執行這種分頁行為根本不是必需的,因為Realm只有在查詢的結果被顯式訪問時才載入物件。
如果對於UI相關或其他實現原因,需要查詢的物件的特定子集,它就像獲取RLMResults
物件一樣簡單,並且只讀出需要的物件。
/ Loop through the first 5 Dog objects
// restricting the number of objects read from disk
RLMResults<Dog *> *dogs = [Dog allObjects];
for (NSInteger i = 0; i < 5; i++) {
Dog *dog = dogs[i];
// ...
}
Realms
Realms
The Default Realm
你可能已經注意到,我們已經通過呼叫[RLMRealm defaultRealm]
初始化了對我們的realm變數的訪問。該方法返回一個RLMRealm物件,對映到應用程式的文件資料夾(iOS)或應用程式支援資料夾(OS X)下的名為“default.realm”的檔案。
Realm API中的許多方法都有接受RLMRealm
例項的版本和使用預設領域的便利版本。例如,[RLMObject allObjects]
等價於[RLMObject allObjectsInRealm:[RLMRealm defaultRealm]]
。
請注意,預設的Realm建構函式和預設的Realm方便方法不允許錯誤處理;你應該只使用它們時,初始化領域不能失敗。有關詳細資訊,請參閱錯誤處理
Realm Configuration
配置諸如儲存Realm檔案的位置等操作是通過RLMRealmConfiguration
來完成的。每次需要Realm例項時,配置都可以傳遞到[RLMRealm realmWithConfiguration:config error:&err]
,或者您可以將[RLMRealmConfiguration setDefaultConfiguration:config]
設定為用於預設範圍。
例如,假設有一個應用程式,使用者必須登入到你的網路後端,並且希望支援在帳戶之間快速切換。您可以通過執行以下操作,為每個帳戶指定自己的Realm檔案,這些檔案將用作預設Realm:
@implementation SomeClass
+ (void)setDefaultRealmForUser:(NSString *)username {
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// Use the default directory, but replace the filename with the username
config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]
URLByAppendingPathComponent:username]
URLByAppendingPathExtension:@"realm"];
// Set this as the configuration used for the default Realm
[RLMRealmConfiguration setDefaultConfiguration:config];
}
@end
Other Realms
有時,有多個Realm在不同位置持久化有用。例如,除了預設realm,你可能需要在Realm檔案中將一些資料與應用程式捆綁在一起。可以使用以下程式碼執行此操作
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// Get the URL to the bundled file
config.fileURL = [[NSBundle mainBundle] URLForResource:@"MyBundledData" withExtension:@"realm"];
// Open the file in read-only mode as application bundles are not writeable
config.readOnly = YES;
// Open the Realm with the configuration
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
// Read some data from the bundled Realm
RLMResults<Dog *> *dogs = [Dog objectsInRealm:realm where:@"age > 5"];
In-Memory Realms
通常,Realm持久儲存到磁碟,但是也可以通過設定inMemoryIdentifier
而不是RLMRealmConfiguration
上的fileURL來建立純粹在記憶體中操作的領域
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.inMemoryIdentifier = @"MyInMemoryRealm";
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
記憶體Realm不會在應用程式啟動時儲存資料,但是Realm的所有其他功能都會按預期工作,包括查詢,關係和執行緒安全。如果需要靈活的資料訪問,而不需要磁碟永續性的開銷,這是一個有用的選項。
記憶體區域在臨時目錄中建立幾個檔案,以協調跨程序通知等事務。沒有資料實際寫入檔案,除非作業系統由於記憶體壓力需要交換到磁碟
注意:當所有具有特定識別符號的記憶體例項例項超出範圍而沒有引用時,所有資料將為該範圍釋放。建議您在應用程式的持續時間內保持對任何建立的記憶體區域的強引用。
Error Handling
與任何磁碟IO操作一樣,如果資源受到限制,則建立RLMRealm
例項有時可能會失敗。實際上,這隻能在第一次在給定的執行緒上建立一個Realm例項時發生。從同一個執行緒對一個Realm的後續訪問將重用一個快取的例項,並且總是成功。
要在第一次訪問指定執行緒上的Realm時處理錯誤,請提供一個指向錯誤引數的NSError指標:
NSError *error = nil;
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
if (!realm) {
// handle error
}
Copying Objects Between Realms
將Realm物件複製到其他領域與將原始物件傳遞給+ [RLMObject createInRealm:withValue:]
一樣簡單。例如,[MyRLMObjectSubclass createInRealm:otherRealm withValue:originalObjectInstance]
。記住,Realm物件只能從它們第一次建立的執行緒進行訪問,所以這個copy過程只能在同一執行緒上的Realms中使用才有效。
請注意,+ [RLMObject createInRealm:withValue:]
不支援處理迴圈物件圖。不要傳遞包含直接或間接引用回父物件的物件的關係的物件。
Finding a Realm File
如果需要幫助查詢您的應用程式的Realm檔案,請檢查此StackOverflow答案詳細說明
Auxiliary Realm Files
除了標準的.realm檔案,Realm還為其自己的內部操作生成和維護附加的檔案和目錄。
- .realm.lock - 資源鎖的鎖檔案。
- .realm.management - 程序間鎖檔案目錄。
- .realm.note - 通知的命名管道。
這些檔案對.realm資料庫檔案沒有任何影響,如果刪除或替換其父資料庫檔案,則不會導致任何錯誤行為。
當報告Realm問題時,請確保將這些輔助檔案與主.realm檔案一起包含,因為它們包含用於除錯目的的有用資訊。
Bundling a Realm with an App
Class Subsets
Deleting Realm Files
Realm with Background App Refresh
相關推薦
Realm Objective‑C 2.4.3 官方文件的翻譯
開始 Realm Objective-C使能夠以安全,持久和快速的方式有效地編寫應用程式的模型層,例子如下: // Define your models like regular Objective‑C classes @interface Do
授人玫瑰 手留餘香 --紀念python3.2.3官方文件翻譯結束
當你點選看到這篇文章的時候,你已經得到了祝福。一個來自夜深人靜的碼農,在2014年5月19號的01:18分,默默為你獻上祝福。希望你,我和他,每一個在IT行業中奮鬥的人,能找到屬於自己一片天空。 在翻譯結束完3.2.3這份文件後,首先感謝我的客戶經理,當在
Hyperledger Fabric 1.3 官方文件翻譯(三)關鍵概念 (Key Concepts)
身份(Identity) 什麼是身份(What is an Identity)? The different actors in a blockchain network include peers, orderers, client applications,
Hyperledger Fabric 1.3 官方文件翻譯(五)教程 (Tutorials)
構建你的第一個網路(Building Your First Network) These instructions have been verified to work against the latest stable Docker images and t
Python3.6.3官方文件閱讀筆記
Python3.6.4官方文件閱讀筆記 Python3.6.4官方文件閱讀筆記 一、基本格式說明 二、基礎語法以及相關操作模式 (一) 基本資料型別以及操作符
【Gradle官方文件翻譯】起步2:建立構建掃描
構建掃描是對構建的可分享的專門記錄,可以看到“構建中發生了那些行為以及為什麼會發生這種行為”。通過在專案中使用構建掃描外掛,開發者可以免費地在https://scans.gradle.com/上釋出構建掃描。 將要建立的 本文會展示如何在不對任何構建指令碼進行
django 2.1官方文件翻譯-模板(進行中)
django的官方文件在transifex上翻譯,本來想貢獻一下,結果發現那個介面實在是受不了。自己翻吧 模板 作為一個Web框架,Django需要一種動態生成HTML的便捷方式。最常見的方法是使用模板。模板包含HTML輸出的靜態部分以及能插入動態內容的一些特殊語法。有關使用模板建立HT
《Spring Data 官方文件翻譯》preface到2.requirements
Cassandra支援的核心功能可以直接使用,無需呼叫Spring容器的IoC服務。這很像’JdbcTemplate’ 這樣的不使用Spring容器的其他任何服務就可以使用’standalone’ 。要利用Spring Data Cassandra的所有功能(如資源庫支援),您需要使用Spring庫的某些配
Spring Framework 4.0 遷移指南 (官方文件翻譯)
看到Spring Framework4.0釋出的訊息,看了下new future,OneCoder很喜歡spring這種追“時髦”的風格,groovy指令碼配置和Java8都支援了。順便就翻譯了一下官方的遷移指南。對一般使用來說,遷移沒什麼難度。
《Spring Data 官方文件翻譯》3. 其他幫助資源
原文連結 3.其他幫助資源 學習一個新的框架並不總是那麼容易的。在這一章中,我們嘗試提供一份我們認為比較容易遵循的指南,用於開始學習Spring Data Cassandra模型。但是,如果您遇到了問題或者您僅僅想要尋找一些建議,可以自由使用以下連結: 3.1. 技術支援 這裡提供了一些支援
SUIMONO 2.1.3中文文件
Suimono 2.1.3文件 英文原版連結:http://tanukidigital.com/suimono/documentation 參考文章:Suimono Water基礎設定 Suimono 213文件 安裝與快速入門
SpringBoot 2.1.1 官方文件閱讀筆記 part1
2.1.1版本要求: Java 8 至 Java 11 Spring 5.1.3 內建工具支援: Maven 3.3+ Gradle 4.4+ 內建 servlet 容器: Tomcat 9.0 要求 Servlet 4
django 1.8 官方文件翻譯: 2-5-7 自定義查詢
自定義查詢 New in Django 1.7. Django為過濾提供了大量的內建的查詢(例如,exact和icontains)。這篇文件闡述瞭如何編寫自定義查詢,以及如何修改現存查詢的功能。關於查詢的API參考,詳見查詢API參考。 一個簡單的
Cloudera 從5.2.0升級到最新5.8.2的官方文件翻譯
最近把叢集升級了,升級同時把官方文件翻譯了一下。初始文件整理在pages中,怎麼轉換過來格式都不太好看,先發圖片的吧,格式不太好的文字部分在後面。 ----------------------------------------------我是格式不好的文字的分割
ABP官方文件翻譯 2.5 設定管理
設定管理 介紹 每個應用都需要儲存設定,並且在應用的某些地方需要使用這些設定。ABP提供了一個強大的在服務端和客戶端都可以使用的基礎設施儲存/獲取應用、租戶和使用者級別的設定。 一個設定是一個名稱-值字串對,一般存放在資料庫(或其他源)。我們可以儲存非字串值
django 1.8 官方文件翻譯: 2-2-1 執行查詢
執行查詢 一旦你建立好資料模型之後,django會自動生成一套資料庫抽象的API,可以讓你執行增刪改查的操作。這篇文件闡述瞭如何使用這些API。關於所有模型檢索選項的詳細內容,請見。 在整個文件(以及參考)中,我們會大量使用下面的模型,它構成了一個部落格應用
Python3.2官方文件翻譯--異常丟擲和自定義異常
6.4 丟擲異常 Raise語句執行程式設計師強制丟擲一個具體的異常。例如: >>> raise NameError(’HiThere’) Traceback (most recent call last): File "<stdin>", l
django 1.8 官方文件翻譯:2-1-1 模型語法
模型 模型是你的資料的唯一的、權威的資訊源。它包含你所儲存資料的必要欄位和行為。通常,每個模型對應資料庫中唯一的一張表。 基礎: 模型的每個屬性都表示資料庫中的一個欄位。 Django 提供一套自動生成的用於資料庫訪問的API;詳見執行查詢。
Objective-C 程式語言官網文件(五)-屬性的宣告
Declared Properties The Objective-C declared properties feature provides a simple way to declare and implement an object’s accessor methods. Ov
Redis 3.0中文官方文件翻譯計劃(17) ——叢集(中)
使用redis-rb-cluster寫一個示例應用 在後面介紹如何操作Redis叢集之前,像故障轉移或者重新分片這樣的事情,我們需要建立一個示例應用,或者至少要了解簡單的Redis叢集客戶端的互動語義。 我們採用執行一個示例,同時嘗試使節點失效,或者開始重新分