原文 http://git.devzeng.com/blog/simple-usage-of-realm-in-ios.html 主題 Realm iOS開發 Realm是由 Y Combinator 公司孵化的一款支持運行在手機、平板和可穿戴設備上的嵌入式資料庫(旨在取代CoreData和Sqli ...
原文 http://git.devzeng.com/blog/simple-usage-of-realm-in-ios.html 主題 Realm iOS開發
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的徹底免費的, 哪怕你用於商業軟體。