iOS CoreData介紹和使用(以及一些注意事項)
最近花了一點時間整理了一下CoreData回论,對于經(jīng)常使用SQLite的我來說赫粥,用這個真的有點用不慣拒啰,個人覺得實在是沒發(fā)現(xiàn)什么亮點败许,不喜勿噴啊怒允。不過這門技術的出現(xiàn)也有其存在價值,這是不可否認的事實享言,即使是不喜歡我們也得去了解一下峻凫,因為你不用別人會用,這年頭都多人開發(fā)担锤,多學點還是有好處的蔚晨。廢話不多說了乍钻,該開始正經(jīng)事了肛循。
CoreData介紹
CoreData是一個模型層的技術,也是一種持久化技術(數(shù)據(jù)庫)银择,它能將模型對象的狀態(tài)持久化到磁盤里多糠,我們不需要使用SQL語句就能對它進行操作。不過在性能方面是弱于直接使用SQLite的浩考。
CoreData使用
理論我就不多說了夹孔,覺得我說的不夠詳細的可以自行搜索關于更多的CoreData介紹。
- 創(chuàng)建步驟流程
- 第一步先創(chuàng)建.xcdatamodeld文件(New File -> iOS -> Core Data ->Data Model)
名字雖然可以任意取析孽,但最好還是取和自己存儲數(shù)據(jù)庫名字一樣的名字搭伤。這樣可讀性更高些。(ps:這個文件就相當于數(shù)據(jù)庫文件一樣,數(shù)據(jù)庫文件中可以有多個表袜瞬,表中可以有各個字段值怜俐,這里也可以有多個實體,每個實體有各個鍵值)
通過上面的操作就可以創(chuàng)建一個.xcdatamodeld文件邓尤,現(xiàn)在我們點擊這個文件拍鲤,在最下面找到Add Entity按鈕贴谎,進行實體添加。
現(xiàn)在我們添加了一個名字為Entity的實體季稳,這個名字是默認名字擅这,現(xiàn)在我們可以對他進行名字的更改,對它雙擊一下即可修改名字景鼠,或者在xcode右邊的信息欄中也可以修改
通過上面操作我們已經(jīng)創(chuàng)建好了實體的名字仲翎,現(xiàn)在我們需要往實體中添加我們需要的鍵值。(ps:相當于數(shù)據(jù)庫表中的字段)莲蜘,具體操作看圖說話(實體之間的關聯(lián)我就不介紹了谭确,有興趣的可以自行搜索資料,個人覺得會了單個實體創(chuàng)建外加查詢就行票渠,關聯(lián)也無非是找到關聯(lián)的實體中共同的鍵值從而取得另外一個實體對象逐哈,我們可以直接先從一個實體取得指定鍵值對應的屬性,再通過屬性值去查詢另一個實體问顷,只是沒關聯(lián)的那么方便而已)昂秃。
- 第二步創(chuàng)建關聯(lián)類來操控CoreData實體對象(選中.xcdatamodeld文件->xcode菜單欄->Edit->Create NSManagedObject Subclass)
選中自己需要關聯(lián)的.xcdatamodeld文件名稱,點擊下一步即可杜窄。
選中.xcdatamodeld文件中需要關聯(lián)的實體對象肠骆,點擊下一步然后在選擇存儲目錄即可。
完成后會發(fā)現(xiàn)自動生成了實體名稱對應的類和擴展類(Entity.h/.m和Entity+CoreDataProperties.h/.m)
到這里就完成了整一個創(chuàng)建的流程塞耕,個人覺得說的有點過于詳細了(導致看起來有點啰嗦)
- 注意
我在試驗的過程中發(fā)現(xiàn)蚀腿,如果我把關聯(lián)的類從項目中刪除,在對實體名稱再次修改后扫外,重新創(chuàng)建關聯(lián)類莉钙,發(fā)現(xiàn)類名還是原來的實體名稱顯示,可能xcode沒刷新筛谚,反正最后我是刪除實體重新Add Entity之后才有用磁玉,所以為了不必要麻煩,最好還是想好實體名稱后再創(chuàng)建關聯(lián)類驾讲。
- 關聯(lián)類的理解
我就以我自己創(chuàng)建的類來說明
#import "UploadEntity.h"
NS_ASSUME_NONNULL_BEGIN
@interface UploadEntity (CoreDataProperties)
@property (nullable, nonatomic, retain) NSString *fileName;
@property (nullable, nonatomic, retain) NSString *fileSize;
@property (nullable, nonatomic, retain) NSNumber *fileType;
@property (nullable, nonatomic, retain) NSNumber *finishStatus;
@property (nullable, nonatomic, retain) NSData *imageData;
@property (nullable, nonatomic, retain) NSNumber *time;
@property (nullable, nonatomic, retain) NSString *urlPath;
@end
NS_ASSUME_NONNULL_END
該類繼承NSManagedObject類
可以看到在實體中的每一個鍵值都被xcode自動生成了實體類的對象屬性蚊伞,而且對于基本數(shù)據(jù)類型被自動轉成了NSNumber。
每個對象的修飾詞都有nullable吮铭,表示CoreData數(shù)據(jù)庫存儲的對象可能為nil(允許存儲nil时迫,就如數(shù)據(jù)庫一樣,字段值也能為NULL)谓晌,也就是說我們以后從CoreData讀取的數(shù)據(jù)是有可能為nil掠拳。
這個類對象的創(chuàng)建我們不能用以往的[[NSObject alloc] init]方式去創(chuàng)建,因為經(jīng)過驗證直接這樣創(chuàng)建它扎谎,然后對屬性賦值會直接拋出異常碳想,估計內(nèi)部經(jīng)行了斷言操作吧烧董。蘋果API提供了幾個專門創(chuàng)建實體對象的方法,后面我在講胧奔。
因為各種限制的原因逊移,比如創(chuàng)建對象限制等,導致了我不好去封裝龙填,最后不得已想到個折中辦法(下面會講)胳泉。基本這一輪下來我的興趣缺失了很多岩遗。
-
CoreData API介紹
- NSManagedObjectContext
這個對象有點像SQLite對象(個人理解:用來管理.xcdatamodeld中的數(shù)據(jù))扇商。 負責數(shù)據(jù)和應用庫之間的交互(CRUD,即增刪改查宿礁、保存等接口都是用這個對象調(diào)用). 每個 NSManagedObjectContext 和其他 NSManagedObjectContext 都是完全獨立的案铺。 所有的NSManagedObject(個人理解:實體數(shù)據(jù))都存在于NSManagedObjectContext中。 每個NSManagedObjectContext都知道自己管理著哪些NSManagedObject(個人理解:實體數(shù)據(jù)) // 創(chuàng)建方式(一般這個對象最好聲明成成員變量) self.context = [[NSManagedObjectContext alloc] init]; // 保存信息(比較重要的操作梆靖,每次更新和插入以及刪除后必須做的操作) NSError *error = nil; BOOL result = [self.context save:&error]; if (!result) { NSLog(@"添加數(shù)據(jù)失斂睾骸:%@",error); if (fail) { fail(error); } } else { NSLog(@"添加數(shù)據(jù)成功"); if (success) { success(); } }
- NSManagedObjectModel
Core Data的模型文件,有點像SQLite的.sqlite文件(個人理解:表示一個.xcdatamodeld文件) // 創(chuàng)建方式 // 1.主動加載指定名稱的.xcdatamodeld資源 //獲取模型路徑 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelName withExtension:@"momd"]; //根據(jù)模型文件創(chuàng)建模型對象 NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; // 2.從應用程序包中加載.xcdatamodeld模型文件 NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
- NSPersistentStoreCoordinator
持久化存儲庫返吻,CoreData的存儲類型(比如SQLite數(shù)據(jù)庫就是其中一種)姑子。 用來將對象管理部分和持久化部分捆綁在一起,負責相互之間的交流(中介一樣) 用來設置CoreData存儲類型和存儲路徑 對象和數(shù)據(jù)庫之間的交互不需要我們來關心测僵,蘋果幫我們做好了街佑。我們只需要面向OC開發(fā) // 創(chuàng)建方式 /** 注意:創(chuàng)建NSPersistentStoreCoordinator前必須創(chuàng)建NSManagedObjectModel 個人理解:好比在一個數(shù)據(jù)庫中創(chuàng)建表前需要設置表的所有字段, 這里傳入NSManagedObjectModel模型(.xcdatamodeld模型文件)捍靠, 感覺就是讓CoreData知道所有模型中的實體中的所有鍵值沐旨, 從而好創(chuàng)建CoreData數(shù)據(jù)庫 */ // 以傳入NSManagedObjectModel模型方式初始化持久化存儲庫 NSPersistentStoreCoordinator *persistent = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; /* 持久化存儲庫的類型: NSSQLiteStoreType SQLite數(shù)據(jù)庫 NSBinaryStoreType 二進制平面文件 NSInMemoryStoreType 內(nèi)存庫,無法永久保存數(shù)據(jù) 雖然這3種類型的性能從速度上來說都差不多剂公,但從數(shù)據(jù)模型中保留下來的信息卻不一樣 在幾乎所有的情景中希俩,都應該采用默認設置吊宋,使用SQLite作為持久化存儲庫 */ // 添加一個持久化存儲庫并設置類型和路徑纲辽,NSSQLiteStoreType:SQLite作為存儲庫 NSError *error = nil; // 名字最好和.xcdatamodeld文件的名字一樣 NSString *sqlPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"xxx.sqlite"]; [persistent addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlPath] options:nil error:&error]; if (error) { NSLog(@"添加數(shù)據(jù)庫失敗:%@",error); if (fail) { fail(error); } } else { NSLog(@"添加數(shù)據(jù)庫成功"); // 設置上下文所要關聯(lián)的持久化存儲庫(這一步千萬不要忘記) self.context.persistentStoreCoordinator = self.persistent; if (success) { success(); } }
- NSEntityDescription
用來描述實體(Entity):相當于數(shù)據(jù)庫表中一組數(shù)據(jù)描述(純屬個人理解) 通過Core Data從數(shù)據(jù)庫中取出的對象,默認情況下都是NSManagedObject對象. NSManagedObject的工作模式有點類似于NSDictionary對象,通過鍵-值對來存取所有的實體屬性. setValue:forkey:存儲屬性值(屬性名為key); valueForKey:獲取屬性值(屬性名為key). 每個NSManagedObject都知道自己屬于哪個NSManagedObjectContext // 創(chuàng)建方式(用于插入數(shù)據(jù)使用:獲得實體,改變實體各個屬性值璃搜,保存后就代表插入) /** 注意:不能用 alloc init方式創(chuàng)建 通過傳入上下文和實體名稱拖吼,創(chuàng)建一個名稱對應的實體對象 (相當于數(shù)據(jù)庫一組數(shù)據(jù),其中含有多個字段) 個人感覺有種先插入一個新的Entity從而獲得Entity这吻,在進行各屬性賦值 */ NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName: entityName inManagedObjectContext:self.context];
- NSManagedObjectContext
-
CoreData的增刪改查
上面說了這么多始終沒描述如何去操作它吊档,現(xiàn)在先說說大概步驟。
- insert
1.根據(jù)Entity名稱和NSManagedObjectContext獲取一個新的NSManagedObject NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.context]; 2.根據(jù)Entity中的鍵值唾糯,一一對應通過setValue:forkey:給NSManagedObject對象賦值 [newEntity setValue:value forKey:key]; 3.保存修改 NSError *error = nil; BOOL result = [self.context save:&error];
- delete
1.通過查詢(設置好查詢條件)請求取得需要刪除的NSManagedObject的所有集合 2.通過for循環(huán)調(diào)用deleteObject:方法進行逐個刪除(個人懷疑這個for循環(huán)會不會導致性能問題)怠硼, 暫時沒發(fā)現(xiàn)其它刪除方法鬼贱。 [self.context deleteObject:entity]; 3.保存修改
- update
1.通過查詢(設置好查詢條件)請求取得需要修改的NSManagedObject的所有集合 2.通過for循環(huán)調(diào)用NSManagedObject對象的setValue:forkey:方法給各個屬性賦值 3.保存修改
- read
1.創(chuàng)建NSFetchRequest查詢請求對象 NSFetchRequest *request = [[NSFetchRequest alloc] init]; 2.設置需要查詢的實體描述NSEntityDescription NSEntityDescription *desc = [NSEntityDescription entityForName:self.entityName inManagedObjectContext:self.context]; request.entity = desc; 3.設置排序順序NSSortDescriptor對象集合(可選) request.sortDescriptors = descriptorArray; 4.設置條件過濾(可選) NSPredicate *predicate = [NSPredicate predicateWithFormat:filterStr]; request.predicate = predicate; 5.執(zhí)行查詢請求 NSError *error = nil; // NSManagedObject對象集合 NSArray *objs = [self.context executeFetchRequest:request error:&error]; // 查詢結果數(shù)目 NSUInteger count = [self.context countForFetchRequest:request error:&error];
從上面可以看出如果我們僅僅是簡單的對CoreData進行增刪改查的操作的話,稍微費點心思的就屬查詢這一塊香璃。里面涉及到了兩個對象NSSortDescriptor和NSPredicate这难,分別用于設置排序和過濾查詢條件的,尤其是NSPredicate葡秒,它不僅僅用于CoreData,還被經(jīng)常用于數(shù)組的過濾姻乓。具體對這兩個對象的介紹我就不說了,感覺這一篇寫多了眯牧。下面我直接上代碼蹋岩。不在多講了。
- insert
-
CoreData個人小封裝
上面提到實體的創(chuàng)建因素導致了封裝重用的難度学少,基本上新建一個.xcdatamodeld文件就得做好特意為它寫一些操作接口的準備剪个。
- CoreDataAPI.h/.m
// // CoreDataAPI.h // TedcallStorage // // Created by tedcall on 16/7/1. // Copyright ? 2016年 pocket. All rights reserved. // #import <Foundation/Foundation.h> @interface CoreDataAPI : NSObject /** * 獲取數(shù)據(jù)庫存儲的路徑 */ @property (nonatomic,copy,readonly) NSString *sqlPath; /** * 獲取.xcdatamodeld文件的名稱 */ @property (nonatomic,copy,readonly) NSString *modelName; /** * 獲取.xcdatamodeld文件中創(chuàng)建的實體的名稱 */ @property (nonatomic,copy,readonly) NSString *entityName; /** * 創(chuàng)建CoreData數(shù)據(jù)庫 * * @param entityName 實體名稱 * @param modelName .xcdatamodeld文件名稱(為nil則主動從程序包加載模型文件) * @param sqlPath 數(shù)據(jù)庫存儲的路徑 * @param success 成功回調(diào) * @param fail 失敗回調(diào) * * @return 返回CoreDataAPI對象 */ - (instancetype)initWithCoreData:(NSString *)entityName modelName:(NSString *)modelName sqlPath:(NSString *)sqlPath success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 插入數(shù)據(jù) * * @param dict 字典中的鍵值對必須要與實體中的每個名字一一對應 * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 查詢數(shù)據(jù) * * @param sequenceKeys 數(shù)組高級排序(數(shù)組里存放實體中的key,順序按自己需要的先后存放即可)版确,實體key來排序 * @param isAscending 是否上升排序 * @param filterStr 過濾語句 * @param success 成功后結果回調(diào) * @param fail 失敗回調(diào) */ - (void)readEntity:(NSArray *)sequenceKeys ascending:(BOOL)isAscending filterStr:(NSString *)filterStr success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail; /** * 刪除數(shù)據(jù) * * @param entity NSManagedObject * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)deleteEntity:(NSManagedObject *)entity success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 更新數(shù)據(jù) * * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail;
- CoreDataAPI.h/.m
@end
```
```objc
//
// CoreDataAPI.m
// TedcallStorage
//
// Created by tedcall on 16/7/1.
// Copyright ? 2016年 pocket. All rights reserved.
//
/**
* 知識點:
NSManagedObject:
通過Core Data從數(shù)據(jù)庫中取出的對象,默認情況下都是NSManagedObject對象.
NSManagedObject的工作模式有點類似于NSDictionary對象,通過鍵-值對來存取所有的實體屬性.
setValue:forkey:存儲屬性值(屬性名為key);
valueForKey:獲取屬性值(屬性名為key).
每個NSManagedObject都知道自己屬于哪個NSManagedObjectContext
NSManagedObjectContext:
負責數(shù)據(jù)和應用庫之間的交互(CRUD禁偎,即增刪改查、保存等接口都在這個對象中).
所有的NSManagedObject都存在于NSManagedObjectContext中阀坏,所以對象和context是相關聯(lián)的
每個 context 和其他 context 都是完全獨立的
每個NSManagedObjectContext都知道自己管理著哪些NSManagedObject
NSPersistentStoreCoordinator:
添加持久化存儲庫如暖,CoreData的存儲類型(比如SQLite數(shù)據(jù)庫就是其中一種)
中間審查者,用來將對象圖管理部分和持久化部分捆綁在一起忌堂,負責相互之間的交流(中介一樣)
NSManagedObjectModel:
Core Data的模型文件
NSEntityDescription:
用來描述實體:相當于數(shù)據(jù)庫表中一組數(shù)據(jù)描述
*/
#import "CoreDataAPI.h"
#import <CoreData/CoreData.h>
@interface CoreDataAPI()
/**
* 數(shù)據(jù)模型對象
*/
@property (nonatomic,strong) NSManagedObjectModel *model;
/**
* 上下文
*/
@property (nonatomic,strong) NSManagedObjectContext *context;
/**
* 持久性存儲區(qū)
*/
@property (nonatomic,strong) NSPersistentStoreCoordinator *persistent;
@end
@implementation CoreDataAPI
- (instancetype)initWithCoreData:(NSString *)entityName modelName:(NSString *)modelName sqlPath:(NSString *)sqlPath success:(void(^)(void))success fail:(void(^)(NSError *error))fail
{
if (self = [super init]) {
// 斷言(實體名稱和存儲路徑是否為nil)
// ...
_entityName = entityName;
_modelName = modelName;
_sqlPath = sqlPath;
// 初始化上下文
self.context = [[NSManagedObjectContext alloc] init];
if (modelName) {
//獲取模型路徑
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelName withExtension:@"momd"];
//根據(jù)模型文件創(chuàng)建模型對象
self.model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
} else { // 從應用程序包中加載模型文件
self.model = [NSManagedObjectModel mergedModelFromBundles:nil];
}
// 以傳入模型方式初始化持久化存儲庫
self.persistent = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
/*
持久化存儲庫的類型:
NSSQLiteStoreType SQLite數(shù)據(jù)庫
NSBinaryStoreType 二進制平面文件
NSInMemoryStoreType 內(nèi)存庫盒至,無法永久保存數(shù)據(jù)
雖然這3種類型的性能從速度上來說都差不多,但從數(shù)據(jù)模型中保留下來的信息卻不一樣
在幾乎所有的情景中士修,都應該采用默認設置枷遂,使用SQLite作為持久化存儲庫
*/
// 添加一個持久化存儲庫并設置類型和路徑,NSSQLiteStoreType:SQLite作為存儲庫
NSError *error = nil;
[self.persistent addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlPath] options:nil error:&error];
if (error) {
NSLog(@"添加數(shù)據(jù)庫失敗:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"添加數(shù)據(jù)庫成功");
// 設置上下文所要關聯(lián)的持久化存儲庫
self.context.persistentStoreCoordinator = self.persistent;
if (success) {
success();
}
}
}
return self;
}
// 添加數(shù)據(jù)
- (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail
{
if (!dict||dict.allKeys.count == 0) return;
// 通過傳入上下文和實體名稱棋嘲,創(chuàng)建一個名稱對應的實體對象(相當于數(shù)據(jù)庫一組數(shù)據(jù)酒唉,其中含有多個字段)
NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:self.entityName inManagedObjectContext:self.context];
// 實體對象存儲屬性值(相當于數(shù)據(jù)庫中將一個值存入對應字段)
for (NSString *key in [dict allKeys]) {
[newEntity setValue:[dict objectForKey:key] forKey:key];
}
// 保存信息,同步數(shù)據(jù)
NSError *error = nil;
BOOL result = [self.context save:&error];
if (!result) {
NSLog(@"添加數(shù)據(jù)失敺幸啤:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"添加數(shù)據(jù)成功");
if (success) {
success();
}
}
}
// 查詢數(shù)據(jù)
- (void)readEntity:(NSArray *)sequenceKeys ascending:(BOOL)isAscending filterStr:(NSString *)filterStr success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail
{
// 1.初始化一個查詢請求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 2.設置要查詢的實體
NSEntityDescription *desc = [NSEntityDescription entityForName:self.entityName inManagedObjectContext:self.context];
request.entity = desc;
// 3.設置查詢結果排序
if (sequenceKeys&&sequenceKeys.count>0) { // 如果進行了設置排序
NSMutableArray *array = [NSMutableArray array];
for (NSString *key in sequenceKeys) {
/**
* 設置查詢結果排序
* sequenceKey:根據(jù)某個屬性(相當于數(shù)據(jù)庫某個字段)來排序
* isAscending:是否升序
*/
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:key ascending:isAscending];
[array addObject:sort];
}
if (array.count>0) {
request.sortDescriptors = array;// 可以添加多個排序描述器痪伦,然后按順序放進數(shù)組即可
}
}
// 4.設置條件過濾
if (filterStr) { // 如果設置了過濾語句
NSPredicate *predicate = [NSPredicate predicateWithFormat:filterStr];
request.predicate = predicate;
}
// 5.執(zhí)行請求
NSError *error = nil;
NSArray *objs = [self.context executeFetchRequest:request error:&error]; // 獲得查詢數(shù)據(jù)數(shù)據(jù)集合
if (error) {
if (fail) {
fail(error);
}
} else{
if (success) {
success(objs);
}
}
}
// 更新數(shù)據(jù)
- (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail
{
NSError *error = nil;
[self.context save:&error];
if (error) {
NSLog(@"刪除失敗:%@",error);
if (fail) {
fail(error);
}
} else {
if (success) {
success();
}
}
}
// 刪除數(shù)據(jù)
- (void)deleteEntity:(NSManagedObject *)entity success:(void(^)(void))success fail:(void(^)(NSError *error))fail
{
// 傳入需要刪除的實體對象
[self.context deleteObject:entity];
// 同步到數(shù)據(jù)庫
NSError *error = nil;
[self.context save:&error];
if (error) {
NSLog(@"刪除失敱⒙唷:%@",error);
if (fail) {
fail(error);
}
} else {
if (success) {
success();
}
}
}
@end
```
- 用法(UploadCoreDataAPI.h/.m)
// // UploadCoreDataAPI.h // TedcallStorage // // Created by tedcall on 16/7/14. // Copyright ? 2016年 pocket. All rights reserved. // #import <Foundation/Foundation.h> @class ResourceModel,DownLoadModel; @interface UploadCoreDataAPI : NSObject /** * 上傳數(shù)據(jù)庫模型名稱 */ @property (nonatomic,copy,readonly) NSString *coreDataModelName; /** * 上傳數(shù)據(jù)庫實體名稱 */ @property (nonatomic,copy,readonly) NSString *coreDataEntityName; /** * 上傳數(shù)據(jù)庫存儲路徑 */ @property (nonatomic,copy,readonly) NSString *coreDataSqlPath; + (instancetype)sharedInstance; /** * 插入上傳記錄 * * @param model 數(shù)據(jù)模型 * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)insertUploadModel:(ResourceModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 更新上傳記錄 * * @param model 數(shù)據(jù)模型 * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)updateUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 刪除一條上傳記錄 * * @param model 數(shù)據(jù)模型 * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)deleteUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 刪除所有上傳記錄 * * @param success 成功回調(diào) * @param fail 失敗回調(diào) */ - (void)deleteAllUploadModel:(void(^)(void))success fail:(void(^)(NSError *error))fail; /** * 查詢上傳數(shù)據(jù)庫所有數(shù)據(jù) * * @param success 成功回調(diào)(finishArray:已完成(DownLoadModel對象數(shù)組) unfinishedArray:未完成(DownLoadModel對象數(shù)組)) * @param fail 失敗回調(diào) */ - (void)readAllUploadModel:(void(^)(NSArray *finishArray,NSArray *unfinishedArray))success fail:(void(^)(NSError *error))fail; @end
// // UploadCoreDataAPI.m // TedcallStorage // // Created by tedcall on 16/7/14. // Copyright ? 2016年 pocket. All rights reserved. // #import "UploadCoreDataAPI.h" #import "CoreDataAPI.h" #import "ResourceModel.h" #import "DownLoadModel.h" static NSString * const modelName = @"Upload"; static NSString * const entityName = @"UploadEntity"; static NSString * const sqliteName = @"Upload.sqlite"; @interface UploadCoreDataAPI() @property (nonatomic,strong) CoreDataAPI *uploadData; @end @implementation UploadCoreDataAPI static UploadCoreDataAPI *uploadCoreData = nil; + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ uploadCoreData = [[UploadCoreDataAPI alloc] init]; }); return uploadCoreData; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (uploadCoreData == nil) { uploadCoreData = [super allocWithZone:zone]; } }); return uploadCoreData; } - (instancetype)init { if (self = [super init]) { [self initUploadCoreData]; } return self; } - (void)initUploadCoreData { _coreDataEntityName = entityName; _coreDataModelName = modelName; _coreDataSqlPath = [[[FileManager shardInstance] getDocumentPath] stringByAppendingPathComponent:sqliteName]; self.uploadData = [[CoreDataAPI alloc] initWithCoreData:self.coreDataEntityName modelName:self.coreDataModelName sqlPath:self.coreDataSqlPath success:^{ NSLog(@"initUploadCoreData success"); } fail:^(NSError *error) { NSLog(@"initUploadCoreData fail"); }]; } #pragma mark - -- 插入上傳記錄 - (void)insertUploadModel:(ResourceModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail { NSString *fileName = model.fileName; NSString *fileSize = [NSString stringWithFormat:@"%.2lf",model.size]; NSString *urlPath = model.path; NSNumber *time = [NSNumber numberWithInt:[[DateManager sharedInstance] getSecondsSince1970]]; NSNumber *fileType = [NSNumber numberWithInt:model.fileType]; NSNumber *finishStatus = [NSNumber numberWithBool:NO]; NSDictionary *dict = NSDictionaryOfVariableBindings(fileName,fileSize,urlPath,time,fileType,finishStatus); [self.uploadData insertNewEntity:dict success:^{ if (success) { success(); } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } #pragma mark - -- 更新上傳記錄 - (void)updateUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail { NSString *filterStr = [NSString stringWithFormat:@"time = %d AND urlPath = '%@' AND fileName = '%@'",model.time,model.urlPath,model.fileName]; [self.uploadData readEntity:nil ascending:YES filterStr:filterStr success:^(NSArray *results) { if (results.count>0) { NSManagedObject *obj = [results firstObject]; [obj setValue:[NSNumber numberWithBool:model.finishStatus] forKey:@"finishStatus"]; [self.uploadData updateEntity:^{ if (success) { success(); } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } #pragma mark - -- 刪除一條上傳記錄 - (void)deleteUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail { NSString *filterStr = [NSString stringWithFormat:@"time = %d AND urlPath = '%@' AND fileName = '%@'",model.time,model.urlPath,model.fileName]; [self.uploadData readEntity:nil ascending:YES filterStr:filterStr success:^(NSArray *results) { if (results.count>0) { NSManagedObject *obj = [results firstObject]; [self.uploadData deleteEntity:obj success:^{ if (success) { success(); } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } #pragma mark - -- 刪除所有上傳記錄 - (void)deleteAllUploadModel:(void(^)(void))success fail:(void(^)(NSError *error))fail { [self.uploadData readEntity:nil ascending:YES filterStr:nil success:^(NSArray *results) { for (NSManagedObject *obj in results){ [self.uploadData deleteEntity:obj success:^{ if (success) { success(); } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } #pragma mark - -- 查詢所有上傳記錄 - (void)readAllUploadModel:(void(^)(NSArray *finishArray,NSArray *unfinishedArray))success fail:(void(^)(NSError *error))fail { [self.uploadData readEntity:nil ascending:YES filterStr:nil success:^(NSArray *results) { NSMutableArray *finishArray = [NSMutableArray array]; NSMutableArray *unfinishedArray = [NSMutableArray array]; for (NSManagedObject *obj in results) { DownLoadModel *model = [[DownLoadModel alloc] init]; // 獲取數(shù)據(jù)庫中各個鍵值的值 model.fileName = [obj valueForKey:@"fileName"]; model.fileSize = [obj valueForKey:@"fileSize"]; model.urlPath = [obj valueForKey:@"urlPath"]; model.time = [[obj valueForKey:@"time"] intValue]; model.fileType = [[obj valueForKey:@"fileType"] intValue]; model.imageData = [obj valueForKey:@"imageData"]; model.finishStatus = [[obj valueForKey:@"finishStatus"] intValue]; if (model.finishStatus) { [finishArray addObject:model]; } else { [unfinishedArray addObject:model]; } } if (success) { success(finishArray,unfinishedArray); } } fail:^(NSError *error) { if (fail) { fail(error); } }]; } @end
結語:以上純屬個人摸索和個人總結网沾,不對的地方忘指出。其實在實際開發(fā)中不僅僅是增刪改查這么簡單蕊爵,有時候會出現(xiàn)APP已經(jīng)發(fā)布辉哥,但是數(shù)據(jù)庫后續(xù)改變了,這就涉及到數(shù)據(jù)庫的遷移,以及一些數(shù)據(jù)安全問題和線程等都是比較深入的醋旦,有專研精神的可以自行搜索相關資料恒水。互勉K瞧搿?芤ぁ!