iOS-CoreData技术

本文介绍了iOS开发中CoreData的使用方法,包括NSManagedObjectModel、NSPersistentStoreCoordinator及NSManagedObjectContext等核心对象的作用,并探讨了CoreData与FMDB在数据持久化方面的优缺点。

前言

CoreData不是数据库,而是对象模型,它提供了对象-关系映射(ORM)功能,能将OC对象保存到SQLite数据库文件中,也可以将数据库数据还原成OC对象;不需要掌握SQL语法也可以操作数据库,有点类似.Net的EF框架。

 

一、CoreData需要使用几个对象进行操作。NSManagedObjectModel对象,加载模型文件,读取app中的所有实体信息;NSPersistentStoreCoordinator对象,添加持久化库(这里采取SQLite数据库);NSManagedObjectContext对象,拿到这个上下文对象操作实体,进行CRUD操作。如果你是在创建项目的时候就勾选了CoreData,那么会在AppDelegate文件中自动生成相关代码,这里采取自定义封装类的方法,独立封装成单例类。

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface Database : NSObject

+ (Database *)database;
- (void)saveContext;

@property (nonatomic, strong, readonly) NSManagedObjectContext *objectContext;
@property (nonatomic, strong, readonly) NSManagedObjectModel *objectModel;
@property (nonatomic, strong, readonly) NSPersistentStoreCoordinator *store;

@end

#import "Database.h"

@implementation Database

@synthesize objectContext = _objectContext;
@synthesize objectModel = _objectModel;
@synthesize store = _store;

- (void)saveContext {
    
    NSError *saveError = nil;
    NSManagedObjectContext *context = self.objectContext;
    if ([context hasChanges] && ![context save:&saveError]) {
        
        if (saveError) {
            
            NSLog(@"save error -- %@", [saveError userInfo]);
            abort();
        }
    }
}

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

// 创建模型对象
- (NSManagedObjectModel *)objectModel {
    
    if (!_objectModel) {
        
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"ZHModel" withExtension:@"momd"];
        _objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    }
    return _objectModel;
}

// 创建管理模型的上下文对象
- (NSManagedObjectContext *)objectContext {
    
    if (!_objectContext) {
        
        _objectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_objectContext setPersistentStoreCoordinator:self.store];
    }
    return _objectContext;
}

// 创建持久化存储协调器
- (NSPersistentStoreCoordinator *)store {
    
    if (!_store) {
        
        // 设置sqlite本地文件存放地址;
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"ZHModel.sqlite"];
        NSError *error = nil;
        NSLog(@"path -- %@", storeURL);
        
        // 需要数据迁移时,所设置的选项;
        NSDictionary *optionDic = @{
                                    NSMigratePersistentStoresAutomaticallyOption: @(YES),
                                    NSInferMappingModelAutomaticallyOption: @(NO)
                                    };
        
        _store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.objectModel];
        // 此处将NSPersistentStoreCoordinator对象作为对象模型与本地sqlite文件中间的协调器;
        [_store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:optionDic error:&error];
        
        if (error) {
            
            NSLog(@"store error -- %@", [error userInfo]);
            abort();
        }
    }
    return _store;
}

// sqlite文件存放目录;
- (NSURL *)applicationDocumentsDirectory {
    
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

@end

 

二、CoreData并不是线程安全的,对于ManagedObject以及ManagedObjectContext的访问都只能在对应的线程上进行,而不能夸线程。并行方案也有很多种,性能各有不同,一种是Notification方式(简单来说,就是不同的线程使用不同的context进行操作,当一个线程的context发生变化后,利用notification来通知另一个线程Context,另一个线程调用mergeChangesFromContextDidSaveNotification来合并变化);另一种是child/parent context方式(ChildContext和ParentContext是相互独立的。只有当ChildContext中调用Save了以后,才会把这段时间来Context的变化提交到ParentContext中,ChildContext并不会直接提交到NSPersistentStoreCoordinator中, parentContext就相当于它的NSPersistentStoreCoordinator),当ParentContext执行save后,才会把Context的变化保存到本地文件。今天我所讨论的是Notification方式,给出几个关键的地方,Notification方式是共用NSPersistentStoreCoordinator的;

self.mainContext = [Database database].objectContext;// 运行在主队列的context
self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];// 运行在私有队列的context
[self.privateContext setPersistentStoreCoordinator:_mainContext.persistentStoreCoordinator]; // 两者共用着一个persistentStoreCoordinator
    

 

1、并行的解决方案之Notification第一步,子线程中的context添加数据并保存,执行insertData方法。

// 在私有队列中添加保存数据,添加成功后会发出NSManagedObjectContextDidSaveNotification通知;
- (void)insertData {
    
    TestEntity2 *testEntity = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity2" inManagedObjectContext:self.privateContext];
    testEntity.title = [NSString stringWithFormat:@"entity%u", arc4random() % 100];
    
    [self.privateContext performBlock:^{
        
        NSError *saveError = nil;
        if ([self.privateContext hasChanges]) {
            
            [self.privateContext save:&saveError];
        }
    }];
}

 

2、privateContext保存成功后,发出NSManagedObjectContextDidSaveNotification通知,mainContext通过mergeChangesFromContextDidSaveNotification合并context的变化。

// 接收到数据变化保存的通知,主队列执行合并操作。
mergeObject = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {
        
        if ([note.object isEqual:self.privateContext]) {
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                [self.mainContext performBlock:^{
                    
                    [self.mainContext mergeChangesFromContextDidSaveNotification:note];
                    [self fetchData];
                }];
            });
        }
    }];

 

总结

持久化存储框架CoreData,FMDB,两者在项目中应用广泛,但不同之处也很明显。

1、CoreData不是线程安全的,而FMDB是线程安全的(使用FMDatabaseQueue);

2、我的理解CoreData数据迁移的不同,比如数据库表的结构删除字段或者是修改字段名,由于SQLite不支持删除数据表的列以及修改字段名,所以FMDB需要编写SQL语句逻辑(重新创建新表、然后填充旧数据、删除旧表以及修改新表名称),CoreData则在新的对象模型中做新旧表的字段对应和删除对象模型的属性。

3、本人喜欢使用FMDB,原因很简单就是喜欢比较透明的编码方式。

转载于:https://my.oschina.net/u/1450995/blog/864640

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值