投稿文章,作者:劉小壯(簡書)
導讀:
認識CoreData—初識CoreData
認識CoreData—基礎使用
認識CoreData—使用進階
認識CoreData—高級用法
認識CoreData—多線程
正文:
到目前為止,已經將CoreData相關的知識點都講完了。
在這篇文章中,主要講一個CoreData第三方庫-MagicalRecord。目前為止這個第三方在Github上有9500+的Star,是所有CoreData第三方庫中使用最多、功能最全的。在文章的後面還會對CoreData做一個總結,以及對本系列所有文章做一個總結。
文章中如有疏漏或錯誤,還請各位及時提出,謝謝!
MagicalRecord
CoreData是蘋果自家推出的一個持久化框架,使用起來更加面向對象。但是在使用過程中會出現大量代碼,而且CoreData學習曲線比較陡峭,如果掌握不好,在使用過程中很容易造成其他問題。
國外開發者開源了一個基於CoreData封裝的第三方——MagicalRecord,就像是FMDB封裝SQLite一樣,MagicalRecord封裝的CoreData,使得原生的CoreData更加容易使用。並且MagicalRecord降低了CoreData的使用門檻,不用去手動管理之前的PSC、MOC等對象。
根據Github上MagicalRecord的官方文檔,MagicalRecord的優點主要有三條:
1. 清理項目中CoreData代碼
2. 支持清晰、簡單、一行式的查詢操作
3. 當需要優化請求時,可以獲取NSFetchRequest進行修改
添加MagicalRecord到項目中
將MagicalRecord添加到項目中,和使用其他第三方一樣,可以通過下載源碼和CocoaPods兩種方式添加。
1. 從Github下載MagicalRecord源碼,將源碼直接拖到項目中,後續需要手動更新源碼。
2. 也可以通過CocoaPods安裝MagicalRecord,需要在Podfile中加入下面命令,後續只需要通過命令來更新。
pod "MagicalRecord"
在之前創建新項目時,通過勾選"Use Core Data"的方式添加CoreData到項目中,會在AppDelegate文件中生成大量CoreData相關代碼。如果是大型項目,被占用的位置是很重要的。而對於MagicalRecord來說,只需要兩行代碼即可。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 初始化CoreData堆棧,也可以指定初始化某個CoreData堆棧 [MagicalRecord setupCoreDataStack]; return YES; } - (void)applicationWillTerminate:(UIApplication *)application { // 在應用退出時,應該調用cleanUp方法 [MagicalRecord cleanUp]; }
MagicalRecord是支持CoreData的.xcdatamodeld文件的,使得CoreData這一優點可以繼續使用。建立數據結構時還是像之前使用CoreData一樣,通過.xcdatamodeld文件的方式建立。
模型文件
支持iCloud
CoreData是支持iCloud的,MagicalRecord對iCloud相關的操作也做了封裝,只需要使用MagicalRecord+iCloud.h類中提供的方法,就可以進行iCloud相關的操作。
例如下面是MagicalRecord+iCloud.h中的一個方法,需要將相關參數傳入即可。
+ (void)setupCoreDataStackWithiCloudContainer:(NSString *)containerID localStoreNamed:(NSString *)localStore;
創建上下文
MagicalRecord對上下文的管理和創建也比較全面,下面是MagicalRecord提供的部分創建和獲取上下文的代碼。因為是給NSManagedObjectContext添加的Category,可以直接用NSManagedObjectContext類調用,使用非常方便。
但是需要注意,雖然系統幫我們管理了上下文對象,對於耗時操作仍然要放在後台線程中處理,並且在主線程中進行UI操作。
+ [NSManagedObjectContext MR_context] 設置默認的上下文為它的父級上下文,並發類型為NSPrivateQueueConcurrencyType
+ [NSManagedObjectContext MR_newMainQueueContext] 創建一個新的上下文,並發類型為NSMainQueueConcurrencyType
+ [NSManagedObjectContext MR_newPrivateQueueContext] 創建一個新的上下文,並發類型為NSPrivateQueueConcurrencyType
+ [NSManagedObjectContext MR_contextWithParent:] 創建一個新的上下文,允許自定義父級上下文,並發類型為NSPrivateQueueConcurrencyType
+ [NSManagedObjectContext MR_contextWithStoreCoordinator:] 創建一個新的上下文,並允許自定義持久化存儲協調器,並發類型為NSPrivateQueueConcurrencyType
+ [NSManagedObjectContext MR_defaultContext] 獲取默認上下文對象,項目中最基礎的上下文對象,並發類型是NSMainQueueConcurrencyType
增刪改查
MagicalRecord對NSManagedObject添加了一個Category,將增刪改查等操作放在這個Category中,使得這些操作可以直接被NSManagedObject類及其子類調用。
.1. 增
對於托管模型的創建非常簡單,不需要像之前還需要進行上下文的操作,現在這都是MagicalRecord幫我們完成的。
// 創建並插入到上下文中 Employee *emp = [Employee MR_createEntity];
.2. 刪
// 從上下文中刪除當前對象 [emp MR_deleteEntity];
.3. 改
// 獲取一個上下文對象 NSManagedObjectContext *defaultContext = [NSManagedObjectContext MR_defaultContext]; // 在當前上下文環境中創建一個新的Employee對象 Employee *emp = [Employee MR_createEntityInContext:defaultContext]; emp.name = @"lxz"; emp.brithday = [NSDate date]; emp.height = @1.7; // 保存修改到當前上下文中 [defaultContext MR_saveToPersistentStoreAndWait];
.4. 查
// 執行查找操作,並設置排序條件 NSArray *empSorted = [Employee MR_findAllSortedBy:@"height" ascending:YES];
自定義NSFetchRequest
下面示例代碼中,Employee根據已有的employeeFilter謂詞對象,創建了employeeRequest請求對象,並將請求對象做修改後,從MOC中獲取請求結果,實現自定義查找條件。
NSPredicate *employeeFilter = [NSPredicate predicateWithFormat:@"name LIKE %@", @"*lxz*"]; NSFetchRequest *employeeRequest = [Employee MR_requestAllWithPredicate:employeeFilter]; employeeRequest.fetchOffset = 10; employeeRequest.fetchLimit = 10; NSArray *employees = [Employee MR_executeFetchRequest:employeeRequest];
參數設置
.1. 可以通過修改MR_LOGGING_DISABLED預編譯指令的值,控制log打印。
#define MR_LOGGING_DISABLED 1
.2.MagicalRecord在DEBUG模式下,對模型文件發生了更改,並且沒有創建新的模型文件版本。MagicalRecord默認會將舊的持久化存儲刪除,創建新的持久化存儲。
MagicalRecord中文文檔
MagicalRecord的使用方法還有很多,這裡只是將一些比較常用的拿出來講講,其他就不一一講解了。在Github上有國人翻譯的MagicalRecord官方文檔,翻譯的非常全面,而且是實時更新的。
這篇文章關於MagicalRecord的部分,也是參考文章來寫的,我這裡就犯了個懶……
MagicalRecord中文文檔
CoreData優缺點總結
無論是什麼東西,肯定不會是絕對完美的,CoreData也是如此。CoreData被設計出來後,對比其他本地持久化方案有自己獨有的優勢,也有比較嚴重的問題。
對於一個本地持久化方案的選取,還是要根據公司業務需求,來選擇一個適合項目的方案,並沒有哪個方案是萬能的。
優點
可以設置關聯關系,也就是之前講過的關聯屬性,關聯屬性可以和當前對象一起被MOC操作。
例如Company關聯一個Person對象,對Company進行操作時,也可以通過點語法從Company中獲取Person,Person的修改會隨著Company一起被持久化。
如果用SQLite實現起來是很麻煩的,但CoreData可以很容易的完成,這也是CoreData更加面向對象的一種體現。
更加面向對象,將之前Model層的表示和持久化合二為一。把數據庫的交互和對象的轉換封裝起來,使用時不需要接觸到任何SQLite相關的代碼,直接使用托管對象即可。
開發效率比較快,可以很快的封裝一個基於CoreData實現的Model層,而不需要太多的代碼就可以實現。
可以很好的防范SQL注入的問題。對於SQLite來說,如果是用FMDB並且用?占位符,也可以防范SQL注入的問題。
可視化化效果好且結構清晰。將模型文件內部的結構,以及實體之間的對應關系等,以可視化的結構展現出來。
對OC原生編程支持非常好,支持keyPath操作方式。例如設置NSPredicate查找條件時,可以使用keyPath的點語法設置屬性。而其他持久化存儲對於這點支持的不太好,需要編寫很復雜的查找條件,看起來也不太好理解。
畢竟是Apple自家推出的,所以對OC融合度比較高,可以很好的配合和使用OC對象。
設置一對一或一對多的關系,設置關系後做存儲和查詢也非常方便,這是非常便於開發的。如果對於性能沒有苛刻的要求,並且持久化對象之間關系比較復雜,比較推薦使用CoreData。
缺點
靈活性不如SQLite,CoreData是對SQLite的一個封裝,上層不能直接對數據庫進行操作。處理任何數據都要按照CoreData內部的實現邏輯執行,而不能自定義執行邏輯,對執行邏輯沒有可控性。
進行大量數據處理時比較吃力,性能明顯低於直接操作SQLite數據庫,而且內存占用非常大,需要手動做內存控制。
當執行一個操作時涉及的數據比較多,需要將所有相關的托管對象加載到內存中,而且中間還涉及到對象的轉換等操作。這樣對性能和內存的消耗都是非常大的,和涉及到的數據量成正比。
因為CoreData底層是用SQLite實現的,可以在CoreData的基礎上,直接編寫SQL語句對數據庫進行操作。但是並不推薦這樣做,在一個項目中應該只有一種持久化的主體方案。而且如果這兩種方式混用的話,對於後期維護是非常困難的。
如果出現這樣的需求,最好直接去用SQLite。
CoreData入門門檻比較高,很難很好的掌握。
很多人都說CoreData不好用,這個原因很大一部分都是因為使用方式的問題。CoreData框架學習難度比較大,導致很多人都只是簡單的使用CoreData,這些用法很多都是不合理的,很多的高級用法並沒有用到。
寫在最後
到目前為止CoreData系列的六篇文章就都寫完了,文章中可能存在一些沒有注意的問題,還請各位提出。博客中包括CoreData在內的所有文章永久更新維護,會不斷將新知識添加到對應的文章中,也會對落後的文章進行重寫。
在第一篇文章中也說到,我接觸CoreData時間也不是很長,這系列文章更像是我學習的一個總結。但是我確實是很認真的在寫,文章內容也是檢查了很多遍,防止錯字或者語法問題。知識點總結的還是比較全面的,在後續我還會更深入的學習CoreData,也可能會推出後續文章。
許多人對於CoreData有很多意見,認為CoreData有各種各樣的問題,這並不是空穴來風。在我學習CoreData的過程中,也發現CoreData確實存在諸多問題,例如查詢性能略差、靈活性等。所以在使用CoreData的時候,還是根據公司業務需求來權衡是否使用CoreData。