Realm是由 Y Combinator
公司孵化的一款支持運行在手機、平板和可穿戴設備上的嵌入式數據庫(旨在取代CoreData和Sqlite)。Realm並不是對Core Data的簡單封裝,相反地,Realm並不是基於Core Data,也不是基於SQLite所構建的。它擁有自己的數據庫存儲引擎,可以高效且快速地完成數據庫的構建操作。
Realm可以輕松地移植到項目當中,並且絕大部分常用的功能(比如說插入、查詢等等)都可以用一行簡單的代碼輕松完成!目前支持Objective-C、Swift和Java三種語言,也就是說能在iOS、Android和Mac上面跨平台使用。
綜上,Realm主要有以下幾個優點:
-
Easy to Use(簡單易用):Core Data和SQLite冗余、繁雜的知識和代碼足以嚇退絕大多數剛入門的開發者,而換用Realm,則可以極大地減少學習代價和學習時間,讓應用及早用上數據存儲功能。
-
Cross-Platform(跨平台):現在絕大多數的應用開發並不僅僅只在iOS平台上進行開發,還要兼顧到Android平台的開發。為兩個平台設計不同的數據庫是愚蠢的,而使用Realm數據庫,iOS和Android無需考慮內部數據的架構,調用Realm提供的API就可以完成數據的交換,實現“一個數據庫,兩個平台無縫銜接”。
-
Fast(高效):Realm相比使用CoreData和原生的SQLite來說速度更快更加高效,而且代碼量更少。
快速集成Realm
1、下載最新的 Realm 更新包,解壓zip文件
2、將 ios/static
目錄下面的 Realm.framework
文件拖到項目里面(確保Copy items if needed選中)
3、在 target -> Build Phases -> Link Binary with Libraries
中添加 libc++.dylib
說明:
(1)對於使用Swift的童鞋,請講Swift/RLMSupport.swift文件拖到項目中(確保Copy items if needed選中)
(2)推薦使用Cocoapods進行安裝,在Podfile中添加 pod 'Realm'
即可
(3)也可以自行到Github上面下載代碼進行編譯,此處不作過多的介紹
運行環境:
(1)支持 >= iOS7.0, >= OS X 10.9, 及WatchKit
(2)推薦使用Xcode 5以上的IDE,支持Swift
輔助工具和插件的安裝
1、Realm Browser
Realm官方非常貼心的向開發者提供了一個用於查看喝編輯Realm數據的工具 Realm Browser
.
在上面下載的更新包的 browser/
下面有個Realm Browser拖到Application文件夾或者是直接打開都行。另外可以使用菜單的 tool -> generate demo datebase
,生成測試數據用於測試Realm數據庫的使用
2、Xcode Plugin(Xcode8之后好像蘋果大大不再支持Xcode插件,如果硬是要使用插件,還是有辦法的,請自行谷歌)
在Realm中使用到最多的是Realm Model(繼承自RLMObject的類,后面有介紹)。官方提供了一個Xcode的插件讓我們在創建模型變得非常輕松
安裝使用:
(1)最簡單的安裝方式是通過Alcatraz,搜索 RealmPlugin
直接安裝
(2)或者是打開zip文件夾下面的 plugin/RealmPlguin.xcodeproj
,build一下就安裝好了
安裝完后重啟Xcode生效,在創建model的時候選擇New File(或⌘N),選擇Realm按照要求輸入model的名字就OK啦。
Realm的使用
1、構建數據庫
Realm提供了三種方式創建數據庫,一種是存儲在默認路徑下的數據庫,一種是我們可以自己指定數據庫文件的存儲路徑和只讀屬性,另外還可以使用內存數據庫。
(1)默認Realm數據庫
RLMRealm *realm = [RLMRealm defaultRealm];
可以通過: [RLMRealm defaultRealmPath]
查看默認存儲的路徑。
(2)自定義Realm數據庫
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *dbPath = [docPath stringByAppendingPathComponent:@"db/db.realm"]; RLMRealm *realm = [RLMRealm realmWithPath:dbPath];
或者是
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *dbPath = [docPath stringByAppendingPathComponent:@"db/db.realm"]; RLMRealm *realm = [RLMRealm realmWithPath:dbPath readOnly:YES error:nil];
其中readOnly表示創建的數據庫是只讀數據庫。
(3)內存數據庫
正常的Realm數據庫是存儲在硬盤上的, 但你也可以通過使用 + (instancetype)inMemoryRealmWithIdentifier:(NSString *)identifier;
來創建一個內存數據庫。
RLMRealm *realm = [RLMRealm inMemoryRealmWithIdentifier:@"test"];
注意:內存數據庫在每次程序退出時不會保存數據。如果某個內存Realm實例沒有被引用,所有的數據在實例對象釋放的適合也會被釋放。建議你在app中用強引用來鉗制所有新建的內存Realm數據庫實例。
2、數據模型
Realm的數據模型是用傳統的Objective-C接口(interface)和屬性(@property)定義的。 只要定義 RLMObject
的一個子類或者一個現成的模型類,你就能輕松創建一個Realm的數據模型對象。Realm模型對象和其他的Objective-c的功能很相似–你可以給它們添加你自己的方法和protocol然后和其他的對象一樣使用。 唯一的限制就是從它們被創建開始,只能在一個進程中被使用。
如果已經安裝了Realm Xcode插件,在 New File
對話框中會有一個很漂亮的樣板,你可以用它來創建interface和implementation文件。
用一個對象來表示一篇文章(Articl),創建的數據模型如下:
Article.h
@interface Article : RLMObject @property NSString *num;//序號 @property NSString *title;//標題 @property NSString *link;//鏈接地址 @property NSString *author;//作者 @property NSString *tag;//標簽分類 @property NSInteger weight;//權重 @end RLM_ARRAY_TYPE(Article)
Article.m
@implementation Article //主鍵 + (NSString *)primaryKey { return @"num"; } //需要添加索引的屬性 + (NSArray *)indexedProperties { return @[@"title"]; } //默認屬性值 + (NSDictionary *)defaultPropertyValues { return @{@"author":@"zengjing"}; } //忽略的字段 + (NSArray *)ignoredProperties { return @[@"weight"]; } @end
說明:
(1)Realm支持以下的屬性(property)種類:BOOL, bool, int, NSInteger, long, float, double, CGFloat, NSString, NSDate 和 NSData。
(2)你可以使用 RLMArray<Object>
和 RLMObject
來模擬對一或對多的關系(Realm也支持RLMObject繼承)
(3)Realm忽略了Objective-C的property attributes(如nonatomic, atomic, strong, copy, weak 等等)。 所以,推薦在創建模型的時候不要使用任何的property attributes。但是,假如你設置了,這些attributes會一直生效直到RLMObject被寫入realm數據庫。
(4)定義了 RLM_ARRAY_TYPE(Article)
這個宏表示支持 RLMArray<Article>
該屬性
(5)另外Realm提供了以下幾個方法供對屬性進行自定義:
1) + (NSArray *)indexedProperties;
: 可以被重寫來來提供特定屬性(property)的屬性值(attrbutes)例如某個屬性值要添加索引。
2) + (NSDictionary *)defaultPropertyValues;
: 為新建的對象屬性提供默認值。
3) + (NSString *)primaryKey;
: 可以被重寫來設置模型的主鍵。定義主鍵可以提高效率並且確保唯一性。
4) + (NSArray *)ignoredProperties;
:可以被重寫來防止Realm存儲模型屬性。
3、數據增刪改查
(1)存儲數據
創建數據模型對象:
Article *article = [[Article alloc] init];
article.num = @"1"; article.title = @"iOS開發中集成Reveal"; article.link = @"http://blog.devzeng.com/blog/ios-reveal-integrating.html"; article.tag = @"iOS";
存儲數據:
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction]; [realm addObject:article]; [realm commitWriteTransaction];
(2)刪除數據
1)刪除指定的數據:
- (void)deleteObject:(RLMObject *)object;
2)刪除一組數據:
- (void)deleteObjects:(id)array;
3)刪除全部的數據:
- (void)deleteAllObjects;
(3)修改數據
修改數據如果該條數據不存在則會新建一條數據。
1)針對單個數據進行的修改或新增:
- (void)addOrUpdateObject:(RLMObject *)object;
2)針對一組數據的修改或新增:
- (void)addOrUpdateObjectsFromArray:(id)array;
說明:對於增加、刪除、修改必須要在事務中進行操作。
(5)查詢數據
1)查詢全部數據
RLMResults *results = [Article allObjects];
或指定Realm數據庫:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *realmPath = [path stringByAppendingPathComponent:@"devzeng.realm"]; RLMRealm *realm = [RLMRealm realmWithPath:realmPath]; RLMResults *results = [Article allObjectsInRealm:realm];
2)條件查詢
假設要查詢所有分組是iOS和作者是zengjing的文章:
RLMResults *results = [Article objectsWhere:@"tag = 'iOS' AND author = 'zengjing'"];
也可以使用謂詞查詢:
NSPredicate *pred = [NSPredicate predicateWithFormat:@"tag = '%@' AND author = '%@'", @"iOS", @"zengjing"]; RLMResults *results = [Article objectsWithPredicate:pred];
3)條件排序
假設要查詢所有分組是iOS和作者是zengjing的文章,然后篩選出來的結果按照num字段進行遞增排序:
RLMResults *results = [[Article objectsWhere:@"tag = 'iOS' AND author = 'zengjing'"] sortedResultsUsingProperty:@"num" ascending:YES];
4)鏈式查詢(結果過濾)
假設要查詢所有所屬分組是iOS的文章,然后從中篩選出作者是zengjing的數據:
RLMResults *results1 = [Article objectsWhere:@"tag = 'iOS'"]; RLMResults *results2 = [results1 objectsWhere:@"author = 'zengjing'"];
4、通知
每當一次寫事務完成Realm實例都會向其他線程上的實例發出通知,可以通過注冊一個block來響應通知:
self.token = [realm addNotificationBlock:^(NSString *note, RLMRealm * realm) { [_listTableView reloadData]; }];
只要有任何的引用指向這個返回的notification token,它就會保持激活狀態。在這個注冊更新的類里,你需要有一個強引用來鉗制這個token, 因為一旦notification token被釋放,通知也會自動解除注冊。
@property (nonatomic, strong) RLMNotificationToken *token;
另外可以使用下面的方式解除通知:
[realm removeNotification:self.token];
5、數據庫版本遷移
當你和數據庫打交道的時候,時不時的你需要改變數據模型(model),但因為Realm中得數據模型被定義為標准的Objective-C interfaces,要改變模型,就像改變其他Objective-C interface一樣輕而易舉。舉個例子,假設有個數據模型 Person
:
在v1.0中數據模型如下:
// v1.0 @interface Person : RLMObject @property NSString *firstName; @property NSString *lastName; @property int age; @end
升級到v2.0之后將firstName和lastName字段合並為一個字段fullName
// v2.0 @interface Person : RLMObject @property NSString *fullName; // new property @property int age; @end
遷移的邏輯可以為:
[RLMRealm setSchemaVersion:2.0 forRealmAtPath:[RLMRealm defaultRealmPath]
withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) { [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) { if (oldSchemaVersion < 2.0) { newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]]; } }]; }];
當版本升級到3.0時,添加新的屬性email
// v3.0 @interface Person : RLMObject @property NSString *fullName; @property NSString *email; // new property @property int age; @end
遷移的邏輯可以為:
[RLMRealm setSchemaVersion:2.0 forRealmAtPath:[RLMRealm defaultRealmPath]
withMigrationBlock:^(RLMMigration *migration, NSUInteger oldSchemaVersion) { [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) { //處理v2.0的更新 if (oldSchemaVersion < 2.0) { newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]]; } //處理v3.0的更新 if(oldSchemaVersion < 3.0) { newObject[@"email"] = @""; } }]; }];
說明(摘自官方的FAQ)
1、realm的支持庫有多大?
一旦你的app編譯完成,realm的支持庫應該只有1MB左右。我們發布的那個可能有點大(iOS ~37MB, OSX ~2.4MB), 那是因為它們還包含了對其他構架的支持(ARM,ARM64,模擬器的是X86)和一些編譯符號。 這些都會在你編譯app的時候被Xcode自動清理掉。
2、我應該在正式產品中使用realm嗎?
自2012年起,realm就已經開始被用於正式的商業產品中了。正如你預期,我們的objective-c & Swift API 會隨着社區的反饋不斷的完善和進化。 所以,你也應該期待realm帶給你更多的新特性和版本修復。
3、我要付realm的使用費用嗎?
不要, Realm的徹底免費的, 哪怕你用於商業軟件。