Realm是專門為移動端開發的數據庫引擎。它具有跨平臺,簡單易用,速度快,占用空間小,支持java,objec-c,swift語言等特點,迅速的得到了開發者的青睞。項目中使用了Realm,將中間的過程記錄下來以備查閱。
環境
- 系統:OS X 10.11.5,
- Xcode:Version 7.2 (7C68)
- 開發語言:Objective-C
準備
1.下載Realm對應的Objective-C版本。下載地址在這里,選擇realm-cocoa下載源代碼。
2.將Realm集成到項目。
Realm框架支持常用的靜態庫,動態庫,CocoaPads和Carthage 幾種集成方式。
本文使用動態庫的方式。-
首先將下載 Realm 的最新版本并解壓;解壓后文件如下
前往Xcode 工程的”General”設置項中,從ios/dynamic/中將’Realm.framework’拖曳到”Embedded Binaries”選項中。確認Copy items if needed被選中后,點擊Finish按鈕;
-
在項目的”Build Phases”中,創建一個新的”Run Script Phase”,并將
bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework/strip-frameworks.sh"
這條腳本復制到文本框中。
-
下載Realm Browser的Mac應用以便 對.realm數據庫進行讀取和編輯。
同時Xcode也有個Realm Browser的插件。使用Alcatraz安裝即可。由于我使用的Xcode7.2版本。會不支持該插件出現想這樣的錯誤。
PluginLoading: Required plug-in compatibility UUID F41BD31E-2683-44B8-AE7F-5F09E919790E for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/RealmBrowser.xcplugin' not present in DVTPlugInCompatibilityUUIDs```
解決辦法:找到該插件的配置文件,將7.2的UUID添加到配置文件即可。
+ 安裝Xcode 插件
RealmPlugin插件可以快速的創建基于RLMObject的模型對象。

安裝完成后,直接command + N新建對應的模型文件。

####Realm數據模型
Realm數據模型是基于標準 Objective-C 類來進行定義的,使用屬性來完成模型的具體定義。
通過簡單的繼承 RLMObject 或者一個已經存在的模型類,您就可以創建一個新的 Realm 數據模型對象。
構建一個銀行卡模型BankInfo
import <Foundation/Foundation.h>
import <Realm/Realm.h>
@interface BankInfo : RLMObject
//銀行卡信息
@property (nonatomic, copy) NSString *bank_accnoalias;
@property (nonatomic, copy) NSString *bank_accname;
@property (nonatomic, copy) NSString *bankname;
@property (nonatomic, copy) NSString *bankid;
@property (nonatomic, copy) NSString *status;
@property (nonatomic, copy) NSString *acc_nature;
@property (nonatomic, copy) NSString *bank_accno;
+(instancetype)bankInfoWithDict:(NSDictionary * )dict;
-(instancetype)initWithBankDict:(NSDictionary *)dict;
@end
RLM_ARRAY_TYPE(BankInfo)
構建持卡人模型Person
import <Realm/Realm.h>
import "BankInfo.h"
@interface Person : RLMObject
@property NSString *name;
@property RLMArray<BankInfo> *banks;
@end
+ 其中在BankInfo模型類的聲明的結尾使用RLM_ARRAY_TYPE(BankInfo)宏來創建一個協議,從而允許 RLMArray<BankInfo> 語法的使用。
然后在Person模型類中聲明屬性```@property RLMArray<BankInfo> *banks;```這樣兩個類構建成了一對多的關系。
> 如果是互相包含的關系呢?
在Realm中通過反向關系來實現即:
```@property (readonly) RLMLinkingObjects *owners;```
先在BankInfo模型類聲明聲明owners屬性,然后重寫 +[RLMObject linkingObjectsProperties] 來指明關系,說明 ownders 中包含了 Person 模型對象。
具體代碼
@interface BankInfo : RLMObject
@property (readonly) RLMLinkingObjects *owners;
@end
RLM_ARRAY_TYPE(BankInfo)
@implementation BankInfo
- (NSDictionary *)linkingObjectsProperties
{
return @{ @"owners": [RLMPropertyDescriptor descriptorWithClass:Person.class propertyName:@"banks"] };
}
@end
@interface Person : RLMObject
@property NSString *name;
@property RLMArray< BankInfo > *banks;
@end
@implementation Person
@end
+ Realm支持以下的屬性類型:BOOL、bool、int、NSInteger、long、long long、float、double、NSString、NSDate、NSData 以及 被特殊類型標記的 NSNumber 。CGFloat 屬性的支持被取消了,因為它的類型不依賴于平臺。
+ 模型類屬性是否可以為nil
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end
@implementation Person
- (NSArray *)requiredProperties {
return @[@"name"];
}
@end
重寫了requiredProperties方法代表name不能為nil
+ 添加索引
重寫 +indexedProperties 方法可以為數據模型中需要添加索引的屬性建立索引
@interface Book : RLMObject
@property float price;
@property NSString *title;
@end
@implementation Book
- (NSArray *)indexedProperties {
return @[@"title"];
}
@end
Realm 支持字符串、整數、布爾值以及 NSDate 屬性作為索引。
+ 添加屬性默認值
重寫+defaultPropertyValues可以在每次對象創建之后為其提供默認值。
@interface Book : RLMObject
@property float price;
@property NSString *title;
@end
@implementation Book
- (NSDictionary *)defaultPropertyValues {
return @{@"price" : @0, @"title": @""};
}
@end
+ 設置主鍵
重寫 +primaryKey 可以設置模型的主鍵。聲明主鍵之后,對象將被允許查詢,更新速度更加高效,并且要求每個對象保持唯一性。 一旦帶有主鍵的對象被添加到 Realm 之后,該對象的主鍵將不可修改。
@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end
@implementation Person
- (NSString *)primaryKey {
return @"id";
}
@end
+ 忽略屬性
重寫 +ignoredProperties 可以防止 Realm 存儲數據模型的某個屬性
@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
####Realm集合
Realm 擁有一系列能夠幫助表示一組對象的類型,我們稱之為『Realm 集合』:
RLMResults類,表示從檢索 中所返回的對象集合。
RLMArray類,表示模型中的對多關系。
RLMLinkingObjects類,表示模型中的反向關系。
RLMCollection協議,定義了所有 Realm 集合所需要遵守的常用接口。
####Realm增刪改查
將常用的增刪改查進行封裝,代碼如下。
// 構建Realm數據庫
RLMRealm *realm = [RLMRealm defaultRealm];
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
[RLMRealmConfiguration setDefaultConfiguration:config];
// Realm內存數據庫
//RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
//config.inMemoryIdentifier = @"MyInMemoryRealm";
//RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
//self.rlmRealm = realm;// 在使用Realm內存數據庫的時候,必須使用強指針引用,如果某個內存 Realm 數據庫實例沒有被引用,那么所有的數據就會被釋放。
// 增加數據
-
(BOOL)realmsInsertData:(NSArray *)data{
NSError *error;
// Add an object
[self.rlmRealm beginWriteTransaction];
for (int i = 0; i < data.count; i++) {BankInfo *obj = [[BankInfo alloc] initWithBankDict:data[i]]; [self.rlmRealm addOrUpdateObject:obj];
}
return [self.rlmRealm commitWriteTransaction:&error];
}
// 查詢數據
-
(id)realmSelectData:(NSString *)object theCondition:(NSString *)condition{
Class cls = NSClassFromString(object);
RLMResults *result = [cls objectsInRealm:self.rlmRealm where:condition];
return result;
}
// 刪除數據
-
(BOOL)realmsDeleteData:(NSString *)object theCondition:(NSString *)condition type:(realmDelType)type{
Class cls = NSClassFromString(object);
if (cls == nil) {
return NO;
}
RLMResults *results = [self realmsselectData:[BankInfo className] theCondition:condition];
if (!results.count) {
return YES;
}
NSError *error = nil;
// 開始事務
[self.rlmRealm beginWriteTransaction];
switch (type) {
case realmDelTypeAll:
[self.rlmRealm deleteObjects:[cls allObjectsInRealm:self.rlmRealm]];
break;
case realmDelTypeFirst:
[self.rlmRealm deleteObject:[cls allObjectsInRealm:self.rlmRealm].firstObject];
break;
case realmDelTypeLast:
[self.rlmRealm deleteObject:[cls allObjectsInRealm:self.rlmRealm].lastObject];
break;
case realmDelTypeOther:
[self.rlmRealm deleteObjects:results];
break;
default:
break;
}
// 提交事務
return [self.rlmRealm commitWriteTransaction:&error];
}
// 更新數據
-
(BOOL)realmsUpdateData:(NSString *)object theCondition:(NSString *)condition property:(NSDictionary *)dict{
Class cls = NSClassFromString(object);
if (cls == nil) {
return NO;
}RLMResults *results = [self realmsselectData:object theCondition:condition];
if (!results.count) {
return YES;
}if (dict == nil) {
return NO;
}// 檢查屬性
if (![self CheckPropertys:object propertyDict:dict]) {
return NO;
}NSError *error = nil;
[self.rlmRealm beginWriteTransaction];//將每條數據的每個 屬性設置為對應的值
for (NSString *updateKey in dict.allKeys) {
[results setValue:dict[updateKey] forKeyPath:updateKey];
}
// 如果沒有值,就新插入一條數據
//[cls createOrUpdateInRealm:self.rlmRealm withValue:dict];return [self.rlmRealm commitWriteTransaction:&error];
}
// 檢查該類中是否有該屬性
-
(BOOL)CheckPropertys:(NSString *)object propertyDict:(NSDictionary *)dict{
Class cls = NSClassFromString(object);
// 屬性字符串數組
NSMutableArray *clspropertys = [NSMutableArray array];unsigned pCount;
objc_property_t *properties = class_copyPropertyList(cls, &pCount);//屬性數組for(int i = 0; i < pCount; i++){
objc_property_t property = properties[i];
NSString *str =[NSString stringWithFormat:@"%s", property_getName(property)];
[clspropertys addObject:str];
//NSLog(@"propertyName:%s",property_getName(property));
//NSLog(@"propertyAttributes:%s",property_getAttributes(property));
}NSArray *keys = dict.allKeys;
for (NSString *dictkey in keys) {
if ([clspropertys containsObject:dictkey]) {
NSLog(@"This class does contain attributes.:%@",dictkey);
}else {
NSLog(@"This class does not contain attributes.:%@",dictkey);
return NO;
}
}
return YES;
}
代碼調用
RLMResults *results = [BankInfo objectsInRealm:self.rlmRealm where:@"bank_accno = '6228481234567891235' "];
NSLog(@"results = %@", results);
NSLog(@"banklistselect = %@", [BankInfo allObjectsInRealm:self.rlmRealm]);
//[self realmsDeleteData:NSStringFromClass([BankInfo class]) theCondition:@"bank_accno = '6228481234567891235' or bank_accno = '6228481234567891242' " type:realmDelTypeOther];
//NSLog(@"banklistDelete = %@", [BankInfo allObjectsInRealm:self.rlmRealm]);
[self realmsUpdateData:NSStringFromClass([BankInfo class]) theCondition:nil property:@{@"status":@"6", @"bank_accnoalias":@"123"}];
NSLog(@"banklistUpdate = %@", [BankInfo allObjectsInRealm:self.rlmRealm]);
[self.rlmRealm beginWriteTransaction];
// 先刪除數據
[self.rlmRealm deleteObjects:[Person allObjects]];
Person *p = [[Person alloc] init];
p.name = @"張三";
[p.banks addObjects:[BankInfo allObjectsInRealm:self.rlmRealm]];
[self.rlmRealm addObject:p];
[self.rlmRealm commitWriteTransaction:nil];
+ Realm中所有有關數據庫的操作都是一個事務。
即所有的代碼都需要去被包含在beginWriteTransaction和commitWriteTransaction之間。
+ Realm查詢結果,Realm將會返回包含 RLMObject 集合的RLMResults實例。RLMResults 的表現和 NSArray 十分相似,并且包含在 RLMResults 中的對象能夠通過索引下標進行訪問。和 NSArray 不同,RLMResults 需要指定類型,并且其當中只能包含RLMObject 子類類型的屬性。
所有的查詢(包括查詢和屬性訪問)在 Realm 中都是延遲加載的,只有當屬性被訪問時,才能夠讀取相應的數據。
+ Realm 支持許多常見的斷言:
比較操作數(comparison operand)可以是屬性名稱或者某個常量,但至少有一個操作數必須是屬性名稱;
比較操作符 ==、<=、<、>=、>、!=, 以及 BETWEEN 支持 int, long, long long, float, double, 以及 NSDate 屬性類型的比較,比如說 age == 45;
相等比較 ==以及!=,比如說[Employee objectsWhere:@"company == %@", company]
比較操作符 == and != 支持布爾屬性;
對于 NSString 和 NSData 屬性來說,我們支持 ==、!=、BEGINSWITH、CONTAINS 以及 ENDSWITH 操作符,比如說 name CONTAINS ‘Ja’;
字符串支持忽略大小寫的比較方式,比如說 name CONTAINS[c] ‘Ja’ ,注意到其中字符的大小寫將被忽略;
Realm 支持以下復合操作符:“AND”、“OR” 以及 “NOT”。比如說 name BEGINSWITH ‘J’ AND age >= 32;
包含操作符 IN,比如說 name IN {‘Lisa’, ‘Spike’, ‘Hachi’};
==、!=支持與 nil 比較,比如說 [Company objectsWhere:@"ceo == nil"]。注意到這只適用于有關系的對象,這里 ceo 是 Company 模型的一個屬性。
通過 ==, != 進行空值比較,比如說 [Company objectsWhere:@"ceo == nil"]; 注意,Realm 將 nil 視為一個特殊的值而不是“缺失值”,不像 SQL 那樣 nil 等于自身。
ANY 比較,比如說 ANY student.age < 21
RLMArray 以及 RLMResults 屬性支持集合表達式:@count、@min、@max、@sum 以及 @avg,例如 [Company objectsWhere:@"employees.@count > 5"] 用以尋找所有超過 5 名雇員的公司。
支持子查詢,不過有限制:
@count 是唯一能應用在 SUBQUERY 表達式中的操作符
SUBQUERY(…).@count 表達式必須與常量進行比較
####其他
在測試的過程中,如果模型類的屬性進行了添加或者刪除操作,重新執行會報錯,重新刪除app的數據即可。
最后執行結果


####參考地址
[官網地址](https://realm.io)
[參考地址1](http://www.cocoachina.com/ios/20150505/11756.html)