Realm筆記

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的模型對象。
![](http://upload-images.jianshu.io/upload_images/1101711-6a8c11404f0cb0f0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
安裝完成后,直接command + N新建對應的模型文件。
![](http://upload-images.jianshu.io/upload_images/1101711-a5af9f65646bfa79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


####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


@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的數據即可。

最后執行結果
![](http://upload-images.jianshu.io/upload_images/1101711-b0aee6127ac7a8d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/1101711-09c7102c120a9b79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容