iOS項目拆分:數(shù)據(jù)本地持久化(4)

Core Data是有蘋果官方提供的框架(#import <CoreData/CoreData.h>)亮蛔,實現(xiàn)數(shù)據(jù)持久化存儲。Core Data實際上是將數(shù)據(jù)庫的創(chuàng)建、表的創(chuàng)建司倚、對象和表的轉(zhuǎn)換等操作封裝起來,極大的簡化了操作篓像。使用Core Data進?數(shù)據(jù)庫存取不需要手動創(chuàng)建數(shù)據(jù)庫动知,創(chuàng)建數(shù)據(jù)庫的過程完全由Core Data框架自動完成,使用者需要做的就是把模型創(chuàng)建起來员辩。

Core Date與SQLite相比較盒粮,SQLite比較原始,操作比較復(fù)雜奠滑,使用的是C的函數(shù)對數(shù)據(jù)庫進行操作丹皱,但是SQLite可控性更強,并且能夠跨平臺宋税。

以下是Core Data操作中經(jīng)常使用的幾個類:

1摊崭、NSManagedObjectModel:被管理的對象模型,相當(dāng)于實體弃甥,不過它包含 了實體間的關(guān)系爽室。
2、NSManagedObjectContext:被管理的對象上下文淆攻,相當(dāng)于操作實際內(nèi)容 作用:插入數(shù)據(jù) 查詢 更新 刪除阔墩。
3、NSPersistentStoreCoordinator:持久化存儲助理瓶珊,用于數(shù)據(jù)庫的連接器啸箫。
4、NSFetchRequest :獲取數(shù)據(jù)的請求伞芹,用于數(shù)據(jù)查詢忘苛,相當(dāng)于查詢語句蝉娜。
5、NSPredicate:相當(dāng)于查詢條件扎唾。
6召川、NSEntityDescription:實體結(jié)構(gòu)。下面胸遇,講解Core Data的簡單使用

在創(chuàng)建項目的時候可以選擇使用Core Data荧呐,項目創(chuàng)建成功后,在AppDelegate類中系統(tǒng)會自動添加相關(guān)代碼纸镊,此外倍阐,還會自動生成一個數(shù)據(jù)模型文件 工程名.xcdatamodeld

圖一:創(chuàng)建工程

AppDelegate.h類中對應(yīng)生成的代碼:

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
//系統(tǒng)自動引入類
@interface AppDelegate : UIResponder <UIApplicationDelegate> 
@property (strong, nonatomic) UIWindow *window;
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)saveContext;
@end

AppDelegate.m類中對應(yīng)生成的代碼,此處注意在XCode中自動生成的代碼較之前有所變動:

#pragma mark - Core Data stack
@synthesize persistentContainer = _persistentContainer;
- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"_23"];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                    
                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                    */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }
    
    return _persistentContainer;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSError *error = nil;
    if ([context hasChanges] && ![context save:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
        abort();
    }
}

如果在創(chuàng)建項目的時候沒有勾選Use Core Data選項逗威,但是在后面需要使用峰搪,需要手動添加一個Data Model文件和手動的添加AppDelegate中的相關(guān)代碼

圖二

注:創(chuàng)建Data Model文件時需要注意,文件名稱要與AppDelegate.m中managedObjectModel方法中提到的文件名稱相匹配,ios8的Xcode排版發(fā)生了一些變動凯旭,需要注意

在生成Data Model文件后概耻,在~~.xcdatamodeld里面添加實體和關(guān)系添加實體如圖所示:

圖三
圖四

注:這里實際上就是向數(shù)據(jù)庫中添加表格和建立表格之間的關(guān)聯(lián)

完成以上步驟,數(shù)據(jù)庫中表格的創(chuàng)建就已經(jīng)完成尽纽,和使用SQLite比較咐蚯,省略了sql語句以及調(diào)用C函數(shù)操作數(shù)據(jù)庫的步驟,另外弄贿,在創(chuàng)建實體的時候不需要設(shè)置主鍵春锋,實體對象的屬性的類型是OC的類型,實體中其他實體對象類型是通過建立關(guān)系添加的差凹。

創(chuàng)建好實體后期奔,可以通過添加NSManagedObject subclass文件(注:創(chuàng)建模型對象的類, "Editor > Create NSManagedobject Subclass"。)危尿,系統(tǒng)可以自動添加實體對應(yīng)的數(shù)據(jù)模型類呐萌,如圖所示:

圖五

圖六

圖七

圖八

圖九

以下是封裝好的CoreDataManaer單例文件

#import <Foundation/Foundation.h>
@interface CoreDataManager : NSObject
/**
 *  單例的初始化類方法
 *
 *  @return CoreDataManager
 */
+ (CoreDataManager *)defaultManager;

/**
 *  添加一個對象模型到數(shù)據(jù)庫中
 *
 *  @param name       模型類的名字
 *  @param dictionary 需要對應(yīng)賦值的屬性
 */
- (void)addManagedObjectModelWithName:(NSString *)name dictionary:(NSDictionary *)dictionary;

/**
 *  查詢對象模型
 *
 *  @param name      模型類的名字
 *  @param predicate 創(chuàng)建一個謂詞
 *  @param sortkeys  用來排序的Keys(注意是個數(shù)組)
 *
 *  @return 返回查到的對象, 在外部使用時應(yīng)與name對應(yīng)
 */
- (NSArray *)fetchManagedObjectModelWithName:(NSString *)name predicate:(NSPredicate *)predicate sortKeys:(NSArray *)sortkeys;

/**
 *  刪除對象模型
 *
 *  @param models 對象模型數(shù)組(注意是數(shù)組, 盡管是刪除一個也要數(shù)組)
 */
- (void)deleteAllManagedObjectModels:(NSArray *)models;
@end
#import "CoreDataManager.h"
#import <CoreData/CoreData.h>

@interface CoreDataManager ()
@property (nonatomic, strong) NSManagedObjectContext * managedObjectContext;
@property (nonatomic, strong) NSManagedObjectModel * managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator * persistentStoreCoordinator;
@end

@implementation CoreDataManager

static CoreDataManager * s_defaultManager = nil;

+ (CoreDataManager *)defaultManager {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        s_defaultManager = [[CoreDataManager alloc] init];
    });
    
    return s_defaultManager;
}

/**
 *  單例的初始化方法, 在init方法中初始化單例類持有的對象
 *
 *  @return 初始化后的對象
 */
- (instancetype)init
{
    self = [super init];
    if (self) {
        
        // 添加觀察者, 當(dāng)ManagerObjectContext發(fā)生變化時調(diào)用saveContext方法
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveContext) name:NSManagedObjectContextObjectsDidChangeNotification object:nil];
    }
    return self;
}

- (void)addManagedObjectModelWithName:(NSString *)name dictionary:(NSDictionary *)dictionary  {
    
    NSManagedObject * managerObject = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:self.managedObjectContext];
    
    [managerObject setValuesForKeysWithDictionary:dictionary];
}

- (NSArray *)fetchManagedObjectModelWithName:(NSString *)name predicate:(NSPredicate *)predicate sortKeys:(NSArray *)sortkeys {
    
    // 實例化查詢請求
    NSFetchRequest * fetchRequest = [NSFetchRequest fetchRequestWithEntityName:name];
    
    // 謂詞搜索如果沒有謂詞, 那么默認查詢?nèi)?    if (predicate) {
        
        [fetchRequest setPredicate:predicate];
    }
    
    // 如果沒有用來排序的key, 那么默認不排序
    if (sortkeys) {
        
        // 如果有排序的Key就先創(chuàng)建一個數(shù)組來接收多個NSSortDescriptor對象(盡管是一個, 因為setSortDescriptors:方法需要數(shù)組作為參數(shù))
        NSMutableArray * sortDescriptorKeys = [NSMutableArray new];
        
        // 遍歷所有的用來排序的key
        for (NSString * key in sortkeys) {
            
            // 每有一個Key, 就使用該key來創(chuàng)建一個NSSortDescriptor
            NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:YES];
            
            // 在sortDescriptorKeys數(shù)組中添加一個NSSortDescriptor元素
            [sortDescriptorKeys addObject:sortDescriptor];
        }
        
        // 查詢請求設(shè)置排序方式
        [fetchRequest setSortDescriptors:sortDescriptorKeys];
    }
    
    // 使用數(shù)組來接收查詢到的內(nèi)容
    NSArray * fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
    
    // 如果數(shù)組為nil
    if (fetchedObjects == nil) {
        
        // 創(chuàng)建一個新的數(shù)組返回, 在外部去做判斷
        fetchedObjects = [NSArray new];
    }
    // 返回查找到的數(shù)組
    return fetchedObjects;
}

- (void)deleteAllManagedObjectModels:(NSArray *)models {
    
    // 遍歷刪除傳進來數(shù)組中的元素對應(yīng)的表內(nèi)容
    for (NSManagedObject * object in models) {
        
        // 使用管理者刪除對象, 數(shù)組中的元素并沒有缺少
        [self.managedObjectContext deleteObject:object];
    }
}

#pragma mark - Core Data stack

- (NSURL *)applicationDocumentsDirectory {
    
//    NSLog(@"%@", [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]);
    
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

/**
 *  模型器的懶加載方法
 *
 *  @return 唯一的模型器
 */
- (NSManagedObjectModel *)managedObjectModel {
    
    if (!_managedObjectModel) {
        
        NSURL * momdPath = [[NSBundle mainBundle] URLForResource:@"PetEfamily" withExtension:@"momd"];
        
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momdPath];
    }
    return _managedObjectModel;
}

/**
 *  鏈接器的懶加載方法
 *
 *  @return 唯一的鏈接器對象
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    
    if (!_persistentStoreCoordinator) {
        
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"LOCoreDataSample.sqlite"];
        [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:@{NSInferMappingModelAutomaticallyOption : @YES, NSMigratePersistentStoresAutomaticallyOption : @YES } error:nil];
    }
    return _persistentStoreCoordinator;
}

/**
 *  管理者的懶加載方法
 *
 *  @return 唯一的管理者對象
 */
- (NSManagedObjectContext *)managedObjectContext {
    
    if (!_managedObjectContext) {
        
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
    }
    return _managedObjectContext;
}

/**
 *  ManagerObjectContext的保存方法
 */
- (void)saveContext {
    
    [self.managedObjectContext save:nil];
} 

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谊娇,隨后出現(xiàn)的幾起案子肺孤,更是在濱河造成了極大的恐慌,老刑警劉巖济欢,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赠堵,死亡現(xiàn)場離奇詭異,居然都是意外死亡法褥,警方通過查閱死者的電腦和手機茫叭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來半等,“玉大人揍愁,你說我怎么就攤上這事呐萨。” “怎么了莽囤?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵谬擦,是天一觀的道長。 經(jīng)常有香客問我朽缎,道長怯屉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任饵沧,我火速辦了婚禮,結(jié)果婚禮上赌躺,老公的妹妹穿的比我還像新娘狼牺。我一直安慰自己,他們只是感情好礼患,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布是钥。 她就那樣靜靜地躺著,像睡著了一般缅叠。 火紅的嫁衣襯著肌膚如雪悄泥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天肤粱,我揣著相機與錄音弹囚,去河邊找鬼。 笑死领曼,一個胖子當(dāng)著我的面吹牛鸥鹉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庶骄,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼毁渗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了单刁?” 一聲冷哼從身側(cè)響起灸异,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎羔飞,沒想到半個月后肺樟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡褥傍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年儡嘶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恍风。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹦狂,死狀恐怖誓篱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情凯楔,我是刑警寧澤窜骄,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站摆屯,受9級特大地震影響邻遏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虐骑,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一准验、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧廷没,春花似錦糊饱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狭归,卻和暖如春夭坪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背过椎。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工室梅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疚宇。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓竞惋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灰嫉。 傳聞我的和親對象是個殘疾皇子拆宛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容