iOS CoreData介紹和使用(以及一些注意事項)

iOS CoreData介紹和使用(以及一些注意事項)

最近花了一點時間整理了一下CoreData,對於經常使用SQLite的我來說,用這個真的有點用不慣,個人覺得實在是沒發現什麼亮點,不喜勿噴啊。不過這門技術的出現也有其存在價值,這是不可否認的事實,即使是不喜歡我們也得去了解一下,因爲你不用別人會用,這年頭都多人開發,多學點還是有好處的。廢話不多說了,該開始正經事了。

CoreData介紹

CoreData是一個模型層的技術,也是一種持久化技術(數據庫),它能將模型對象的狀態持久化到磁盤裏,我們不需要使用SQL語句就能對它進行操作。不過在性能方面是弱於直接使用SQLite的。

CoreData使用

理論我就不多說了,覺得我說的不夠詳細的可以自行搜索關於更多的CoreData介紹。

  • 創建步驟流程
    • 第一步先創建.xcdatamodeld文件(New File -> iOS -> Core Data ->Data Model)

屏幕快照 2016-07-07 下午10.40.16.png

名字雖然可以任意取,但最好還是取和自己存儲數據庫名字一樣的名字。這樣可讀性更高些。(ps:這個文件就相當於數據庫文件一樣,數據庫文件中可以有多個表,表中可以有各個字段值,這裏也可以有多個實體,每個實體有各個鍵值)


屏幕快照 2016-07-07 下午10.40.40.png

通過上面的操作就可以創建一個.xcdatamodeld文件,現在我們點擊這個文件,在最下面找到Add Entity按鈕,進行實體添加。


屏幕快照 2016-07-13 下午8.50.10.png

現在我們添加了一個名字爲Entity的實體,這個名字是默認名字,現在我們可以對他進行名字的更改,對它雙擊一下即可修改名字,或者在xcode右邊的信息欄中也可以修改


屏幕快照 2016-07-13 下午9.09.38.png

通過上面操作我們已經創建好了實體的名字,現在我們需要往實體中添加我們需要的鍵值。(ps:相當於數據庫表中的字段),具體操作看圖說話(實體之間的關聯我就不介紹了,有興趣的可以自行搜索資料,個人覺得會了單個實體創建外加查詢就行,關聯也無非是找到關聯的實體中共同的鍵值從而取得另外一個實體對象,我們可以直接先從一個實體取得指定鍵值對應的屬性,再通過屬性值去查詢另一個實體,只是沒關聯的那麼方便而已)。


屏幕快照 2016-07-13 下午9.17.43.png
  • 第二步創建關聯類來操控CoreData實體對象(選中.xcdatamodeld文件->xcode菜單欄->Edit->Create NSManagedObject Subclass)

屏幕快照 2016-07-13 下午9.35.57.png

選中自己需要關聯的.xcdatamodeld文件名稱,點擊下一步即可。


屏幕快照 2016-07-13 下午9.47.24.png

選中.xcdatamodeld文件中需要關聯的實體對象,點擊下一步然後在選擇存儲目錄即可。


屏幕快照 2016-07-13 下午9.48.06.png

完成後會發現自動生成了實體名稱對應的類和擴展類(Entity.h/.m和Entity+CoreDataProperties.h/.m)


屏幕快照 2016-07-13 下午10.23.22.png

到這裏就完成了整一個創建的流程,個人覺得說的有點過於詳細了(導致看起來有點囉嗦)

  • 注意
    我在試驗的過程中發現,如果我把關聯的類從項目中刪除,在對實體名稱再次修改後,重新創建關聯類,發現類名還是原來的實體名稱顯示,可能xcode沒刷新,反正最後我是刪除實體重新Add Entity之後纔有用,所以爲了不必要麻煩,最好還是想好實體名稱後再創建關聯類。
  • 關聯類的理解

    我就以我自己創建的類來說明

    #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自動生成了實體類的對象屬性,而且對於基本數據類型被自動轉成了NSNumber。

    • 每個對象的修飾詞都有nullable,表示CoreData數據庫存儲的對象可能爲nil(允許存儲nil,就如數據庫一樣,字段值也能爲NULL),也就是說我們以後從CoreData讀取的數據是有可能爲nil。

    • 這個類對象的創建我們不能用以往的[[NSObject alloc] init]方式去創建,因爲經過驗證直接這樣創建它,然後對屬性賦值會直接拋出異常,估計內部經行了斷言操作吧。蘋果API提供了幾個專門創建實體對象的方法,後面我在講。

    • 因爲各種限制的原因,比如創建對象限制等,導致了我不好去封裝,最後不得已想到個折中辦法(下面會講)。基本這一輪下來我的興趣缺失了很多。

  • CoreData API介紹

    • NSManagedObjectContext

       這個對象有點像SQLite對象(個人理解:用來管理.xcdatamodeld中的數據)。
       負責數據和應用庫之間的交互(CRUD,即增刪改查、保存等接口都是用這個對象調用).
       每個 NSManagedObjectContext 和其他 NSManagedObjectContext 都是完全獨立的。
       所有的NSManagedObject(個人理解:實體數據)都存在於NSManagedObjectContext中。
       每個NSManagedObjectContext都知道自己管理着哪些NSManagedObject(個人理解:實體數據)
       // 創建方式(一般這個對象最好聲明成成員變量)
       self.context = [[NSManagedObjectContext alloc] init];
       // 保存信息(比較重要的操作,每次更新和插入以及刪除後必須做的操作)
       NSError *error = nil;
       BOOL result = [self.context save:&error];
       if (!result) {
          NSLog(@"添加數據失敗:%@",error);
          if (fail) {
              fail(error);
          }
       } else {
          NSLog(@"添加數據成功");
          if (success) {
              success();
          }
       }
    • NSManagedObjectModel
      Core Data的模型文件,有點像SQLite的.sqlite文件(個人理解:表示一個.xcdatamodeld文件)
      // 創建方式
      // 1.主動加載指定名稱的.xcdatamodeld資源
      //獲取模型路徑
      NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelName
                                                  withExtension:@"momd"];
      //根據模型文件創建模型對象
      NSManagedObjectModel *model = [[NSManagedObjectModel alloc]
                                          initWithContentsOfURL:modelURL];
       // 2.從應用程序包中加載.xcdatamodeld模型文件                              
       NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    • NSPersistentStoreCoordinator

      持久化存儲庫,CoreData的存儲類型(比如SQLite數據庫就是其中一種)。
      用來將對象管理部分和持久化部分捆綁在一起,負責相互之間的交流(中介一樣)
      用來設置CoreData存儲類型和存儲路徑
      對象和數據庫之間的交互不需要我們來關心,蘋果幫我們做好了。我們只需要面向OC開發
      // 創建方式
      /**
        注意:創建NSPersistentStoreCoordinator前必須創建NSManagedObjectModel
              個人理解:好比在一個數據庫中創建表前需要設置表的所有字段,
                      這裏傳入NSManagedObjectModel模型(.xcdatamodeld模型文件),
                      感覺就是讓CoreData知道所有模型中的實體中的所有鍵值,
                      從而好創建CoreData數據庫              
      */ 
      // 以傳入NSManagedObjectModel模型方式初始化持久化存儲庫
      NSPersistentStoreCoordinator *persistent = [[NSPersistentStoreCoordinator alloc]
                                                    initWithManagedObjectModel:model];
      /*
         持久化存儲庫的類型:
         NSSQLiteStoreType  SQLite數據庫
         NSBinaryStoreType  二進制平面文件
         NSInMemoryStoreType 內存庫,無法永久保存數據
         雖然這3種類型的性能從速度上來說都差不多,但從數據模型中保留下來的信息卻不一樣
         在幾乎所有的情景中,都應該採用默認設置,使用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(@"添加數據庫失敗:%@",error);
          if (fail) {
              fail(error);
          }
      } else {
           NSLog(@"添加數據庫成功");
          // 設置上下文所要關聯的持久化存儲庫(這一步千萬不要忘記)
          self.context.persistentStoreCoordinator = self.persistent;
          if (success) {
              success();
          }
      }
    • NSEntityDescription
      用來描述實體(Entity):相當於數據庫表中一組數據描述(純屬個人理解)
      通過Core Data從數據庫中取出的對象,默認情況下都是NSManagedObject對象.
       NSManagedObject的工作模式有點類似於NSDictionary對象,通過鍵-值對來存取所有的實體屬性.
       setValue:forkey:存儲屬性值(屬性名爲key);
       valueForKey:獲取屬性值(屬性名爲key).
       每個NSManagedObject都知道自己屬於哪個NSManagedObjectContext
      // 創建方式(用於插入數據使用:獲得實體,改變實體各個屬性值,保存後就代表插入)
      /**
        注意:不能用 alloc init方式創建
        通過傳入上下文和實體名稱,創建一個名稱對應的實體對象
        (相當於數據庫一組數據,其中含有多個字段)
        個人感覺有種先插入一個新的Entity從而獲得Entity,在進行各屬性賦值
      */
      NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:
                                                                        entityName 
                                                    inManagedObjectContext:self.context];
  • CoreData的增刪改查

    上面說了這麼多始終沒描述如何去操作它,現在先說說大概步驟。

    • insert
      1.根據Entity名稱和NSManagedObjectContext獲取一個新的NSManagedObject
        NSManagedObject *newEntity = [NSEntityDescription
                                      insertNewObjectForEntityForName:entityName 
                                      inManagedObjectContext:self.context];
      2.根據Entity中的鍵值,一一對應通過setValue:forkey:給NSManagedObject對象賦值
        [newEntity setValue:value forKey:key];
      3.保存修改
        NSError *error = nil;
        BOOL result = [self.context save:&error];
    • delete
      1.通過查詢(設置好查詢條件)請求取得需要刪除的NSManagedObject的所有集合
      2.通過for循環調用deleteObject:方法進行逐個刪除(個人懷疑這個for循環會不會導致性能問題),
        暫時沒發現其它刪除方法。
        [self.context deleteObject:entity];
      3.保存修改
    • update
      1.通過查詢(設置好查詢條件)請求取得需要修改的NSManagedObject的所有集合
      2.通過for循環調用NSManagedObject對象的setValue:forkey:方法給各個屬性賦值
      3.保存修改
    • read
      1.創建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.執行查詢請求
        NSError *error = nil;
        // NSManagedObject對象集合
        NSArray *objs = [self.context executeFetchRequest:request error:&error];
        // 查詢結果數目
        NSUInteger count = [self.context countForFetchRequest:request error:&error];

      從上面可以看出如果我們僅僅是簡單的對CoreData進行增刪改查的操作的話,稍微費點心思的就屬查詢這一塊。裏面涉及到了兩個對象NSSortDescriptor和NSPredicate,分別用於設置排序和過濾查詢條件的,尤其是NSPredicate,它不僅僅用於CoreData,還被經常用於數組的過濾。具體對這兩個對象的介紹我就不說了,感覺這一篇寫多了。下面我直接上代碼。不在多講了。

  • CoreData個人小封裝

    上面提到實體的創建因素導致了封裝重用的難度,基本上新建一個.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
      /**
       *  獲取數據庫存儲的路徑
       */
      @property (nonatomic,copy,readonly) NSString *sqlPath;
      /**
       *  獲取.xcdatamodeld文件的名稱
       */
      @property (nonatomic,copy,readonly) NSString *modelName;
      /**
       *  獲取.xcdatamodeld文件中創建的實體的名稱
       */
      @property (nonatomic,copy,readonly) NSString *entityName;
      
      /**
       *  創建CoreData數據庫
       *
       *  @param entityName 實體名稱
       *  @param modelName  .xcdatamodeld文件名稱(爲nil則主動從程序包加載模型文件)
       *  @param sqlPath    數據庫存儲的路徑
       *  @param success    成功回調
       *  @param fail       失敗回調
       *
       *  @return 返回CoreDataAPI對象
       */
      - (instancetype)initWithCoreData:(NSString *)entityName modelName:(NSString *)modelName sqlPath:(NSString *)sqlPath success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  插入數據
       *
       *  @param dict 字典中的鍵值對必須要與實體中的每個名字一一對應
       *  @param success    成功回調
       *  @param fail       失敗回調
       */
      - (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  查詢數據
       *
       *  @param sequenceKeys 數組高級排序(數組裏存放實體中的key,順序按自己需要的先後存放即可),實體key來排序
       *  @param isAscending  是否上升排序
       *  @param filterStr    過濾語句
       *  @param success      成功後結果回調
       *  @param fail         失敗回調
       */
      - (void)readEntity:(NSArray *)sequenceKeys ascending:(BOOL)isAscending filterStr:(NSString *)filterStr success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  刪除數據
       *
       *  @param entity  NSManagedObject
       *  @param success 成功回調
       *  @param fail    失敗回調
       */
      - (void)deleteEntity:(NSManagedObject *)entity success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  更新數據
       *
       *  @param success 成功回調
       *  @param fail    失敗回調
       */
      - (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      @end
      //
      //  CoreDataAPI.m
      //  TedcallStorage
      //
      //  Created by  tedcall on 16/7/1.
      //  Copyright © 2016年 pocket. All rights reserved.
      //
      
      /**
       *  知識點:
       NSManagedObject:
           通過Core Data從數據庫中取出的對象,默認情況下都是NSManagedObject對象.
           NSManagedObject的工作模式有點類似於NSDictionary對象,通過鍵-值對來存取所有的實體屬性.
           setValue:forkey:存儲屬性值(屬性名爲key);
           valueForKey:獲取屬性值(屬性名爲key).
           每個NSManagedObject都知道自己屬於哪個NSManagedObjectContext
      
       NSManagedObjectContext:
          負責數據和應用庫之間的交互(CRUD,即增刪改查、保存等接口都在這個對象中).
          所有的NSManagedObject都存在於NSManagedObjectContext中,所以對象和context是相關聯的
          每個 context 和其他 context 都是完全獨立的
          每個NSManagedObjectContext都知道自己管理着哪些NSManagedObject
      
       NSPersistentStoreCoordinator:
          添加持久化存儲庫,CoreData的存儲類型(比如SQLite數據庫就是其中一種)
          中間審查者,用來將對象圖管理部分和持久化部分捆綁在一起,負責相互之間的交流(中介一樣)
      
       NSManagedObjectModel:
          Core Data的模型文件
      
       NSEntityDescription:
          用來描述實體:相當於數據庫表中一組數據描述
       */
      
      #import "CoreDataAPI.h"
      #import <CoreData/CoreData.h>
      @interface CoreDataAPI()
      /**
       *  數據模型對象
       */
      @property (nonatomic,strong) NSManagedObjectModel *model;
      /**
       *  上下文
       */
      @property (nonatomic,strong) NSManagedObjectContext *context;
      /**
       *  持久性存儲區
       */
      @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"];
                  //根據模型文件創建模型對象
                  self.model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
              } else { // 從應用程序包中加載模型文件
                  self.model = [NSManagedObjectModel mergedModelFromBundles:nil];
              }
      
              // 以傳入模型方式初始化持久化存儲庫
              self.persistent = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
              /*
               持久化存儲庫的類型:
               NSSQLiteStoreType  SQLite數據庫
               NSBinaryStoreType  二進制平面文件
               NSInMemoryStoreType 內存庫,無法永久保存數據
               雖然這3種類型的性能從速度上來說都差不多,但從數據模型中保留下來的信息卻不一樣
               在幾乎所有的情景中,都應該採用默認設置,使用SQLite作爲持久化存儲庫
               */
              // 添加一個持久化存儲庫並設置類型和路徑,NSSQLiteStoreType:SQLite作爲存儲庫
              NSError *error = nil;
              [self.persistent addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlPath] options:nil error:&error];
              if (error) {
                  NSLog(@"添加數據庫失敗:%@",error);
                  if (fail) {
                      fail(error);
                  }
              } else {
                   NSLog(@"添加數據庫成功");
                  // 設置上下文所要關聯的持久化存儲庫
                  self.context.persistentStoreCoordinator = self.persistent;
                  if (success) {
                      success();
                  }
              }
          }
      
          return self;
      }
      
      // 添加數據
      - (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail
      {
          if (!dict||dict.allKeys.count == 0) return;
          // 通過傳入上下文和實體名稱,創建一個名稱對應的實體對象(相當於數據庫一組數據,其中含有多個字段)
          NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:self.entityName inManagedObjectContext:self.context];
          // 實體對象存儲屬性值(相當於數據庫中將一個值存入對應字段)
          for (NSString *key in [dict allKeys]) {
              [newEntity setValue:[dict objectForKey:key] forKey:key];
          }
          // 保存信息,同步數據
          NSError *error = nil;
          BOOL result = [self.context save:&error];
          if (!result) {
              NSLog(@"添加數據失敗:%@",error);
              if (fail) {
                  fail(error);
              }
          } else {
              NSLog(@"添加數據成功");
              if (success) {
                  success();
              }
          }
      }
      
      // 查詢數據
      - (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:根據某個屬性(相當於數據庫某個字段)來排序
                   *  isAscending:是否升序
                   */
                  NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:key ascending:isAscending];
                  [array addObject:sort];
              }
              if (array.count>0) {
                  request.sortDescriptors = array;// 可以添加多個排序描述器,然後按順序放進數組即可
              }
          }
          // 4.設置條件過濾
          if (filterStr) { // 如果設置了過濾語句
              NSPredicate *predicate = [NSPredicate predicateWithFormat:filterStr];
              request.predicate = predicate;
          }
          // 5.執行請求
          NSError *error = nil;
          NSArray *objs = [self.context executeFetchRequest:request error:&error]; // 獲得查詢數據數據集合
          if (error) {
              if (fail) {
                  fail(error);
              }
          } else{
              if (success) {
                  success(objs);
              }
          }
      }
      
      // 更新數據
      - (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();
              }
          }
      
      }
      
      // 刪除數據
      - (void)deleteEntity:(NSManagedObject *)entity success:(void(^)(void))success fail:(void(^)(NSError *error))fail
      {
          // 傳入需要刪除的實體對象
          [self.context deleteObject:entity];
          // 同步到數據庫
          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
      /**
       *  上傳數據庫模型名稱
       */
      @property (nonatomic,copy,readonly) NSString *coreDataModelName;
      /**
       *  上傳數據庫實體名稱
       */
      @property (nonatomic,copy,readonly) NSString *coreDataEntityName;
      /**
       *  上傳數據庫存儲路徑
       */
      @property (nonatomic,copy,readonly) NSString *coreDataSqlPath;
      + (instancetype)sharedInstance;
      /**
       *  插入上傳記錄
       *
       *  @param model   數據模型
       *  @param success 成功回調
       *  @param fail    失敗回調
       */
      - (void)insertUploadModel:(ResourceModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  更新上傳記錄
       *
       *  @param model   數據模型
       *  @param success 成功回調
       *  @param fail    失敗回調
       */
      - (void)updateUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  刪除一條上傳記錄
       *
       *  @param model   數據模型
       *  @param success 成功回調
       *  @param fail    失敗回調
       */
      - (void)deleteUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  刪除所有上傳記錄
       *
       *  @param success 成功回調
       *  @param fail    失敗回調
       */
      - (void)deleteAllUploadModel:(void(^)(void))success fail:(void(^)(NSError *error))fail;
      
      /**
       *  查詢上傳數據庫所有數據
       *
       *  @param success 成功回調(finishArray:已完成(DownLoadModel對象數組) unfinishedArray:未完成(DownLoadModel對象數組))
       *  @param fail    失敗回調
       */
      - (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];
                  // 獲取數據庫中各個鍵值的值
                  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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章