美文网首页
iOS项目拆分:数据本地持久化(4)

iOS项目拆分:数据本地持久化(4)

作者: 韩发发吖 | 来源:发表于2016-10-27 13:00 被阅读407次

    Core Data是有苹果官方提供的框架(#import <CoreData/CoreData.h>),实现数据持久化存储。Core Data实际上是将数据库的创建、表的创建、对象和表的转换等操作封装起来,极大的简化了操作。使用Core Data进⾏数据库存取不需要手动创建数据库,创建数据库的过程完全由Core Data框架自动完成,使用者需要做的就是把模型创建起来。

    Core Date与SQLite相比较,SQLite比较原始,操作比较复杂,使用的是C的函数对数据库进行操作,但是SQLite可控性更强,并且能够跨平台。

    以下是Core Data操作中经常使用的几个类:

    1、NSManagedObjectModel:被管理的对象模型,相当于实体,不过它包含 了实体间的关系。
    2、NSManagedObjectContext:被管理的对象上下文,相当于操作实际内容 作用:插入数据 查询 更新 删除
    3、NSPersistentStoreCoordinator:持久化存储助理,用于数据库的连接器。
    4、NSFetchRequest :获取数据的请求,用于数据查询,相当于查询语句。
    5、NSPredicate:相当于查询条件。
    6、NSEntityDescription:实体结构。下面,讲解Core Data的简单使用

    在创建项目的时候可以选择使用Core Data,项目创建成功后,在AppDelegate类中系统会自动添加相关代码,此外,还会自动生成一个数据模型文件 工程名.xcdatamodeld

    图一:创建工程

    AppDelegate.h类中对应生成的代码:

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

    AppDelegate.m类中对应生成的代码,此处注意在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();
        }
    }
    

    如果在创建项目的时候没有勾选Use Core Data选项,但是在后面需要使用,需要手动添加一个Data Model文件和手动的添加AppDelegate中的相关代码

    图二

    注:创建Data Model文件时需要注意,文件名称要与AppDelegate.m中managedObjectModel方法中提到的文件名称相匹配,ios8的Xcode排版发生了一些变动,需要注意

    在生成Data Model文件后,在~~.xcdatamodeld里面添加实体和关系添加实体如图所示:

    图三 图四

    注:这里实际上就是向数据库中添加表格和建立表格之间的关联

    完成以上步骤,数据库中表格的创建就已经完成,和使用SQLite比较,省略了sql语句以及调用C函数操作数据库的步骤,另外,在创建实体的时候不需要设置主键,实体对象的属性的类型是OC的类型,实体中其他实体对象类型是通过建立关系添加的。

    创建好实体后,可以通过添加NSManagedObject subclass文件(注:创建模型对象的类, "Editor > Create NSManagedobject Subclass"。),系统可以自动添加实体对应的数据模型类,如图所示:

    图五
    图六
    图七
    图八
    图九

    以下是封装好的CoreDataManaer单例文件

    #import <Foundation/Foundation.h>
    @interface CoreDataManager : NSObject
    /**
     *  单例的初始化类方法
     *
     *  @return CoreDataManager
     */
    + (CoreDataManager *)defaultManager;
    
    /**
     *  添加一个对象模型到数据库中
     *
     *  @param name       模型类的名字
     *  @param dictionary 需要对应赋值的属性
     */
    - (void)addManagedObjectModelWithName:(NSString *)name dictionary:(NSDictionary *)dictionary;
    
    /**
     *  查询对象模型
     *
     *  @param name      模型类的名字
     *  @param predicate 创建一个谓词
     *  @param sortkeys  用来排序的Keys(注意是个数组)
     *
     *  @return 返回查到的对象, 在外部使用时应与name对应
     */
    - (NSArray *)fetchManagedObjectModelWithName:(NSString *)name predicate:(NSPredicate *)predicate sortKeys:(NSArray *)sortkeys;
    
    /**
     *  删除对象模型
     *
     *  @param models 对象模型数组(注意是数组, 尽管是删除一个也要数组)
     */
    - (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) {
            
            // 添加观察者, 当ManagerObjectContext发生变化时调用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];
        
        // 谓词搜索如果没有谓词, 那么默认查询全部
        if (predicate) {
            
            [fetchRequest setPredicate:predicate];
        }
        
        // 如果没有用来排序的key, 那么默认不排序
        if (sortkeys) {
            
            // 如果有排序的Key就先创建一个数组来接收多个NSSortDescriptor对象(尽管是一个, 因为setSortDescriptors:方法需要数组作为参数)
            NSMutableArray * sortDescriptorKeys = [NSMutableArray new];
            
            // 遍历所有的用来排序的key
            for (NSString * key in sortkeys) {
                
                // 每有一个Key, 就使用该key来创建一个NSSortDescriptor
                NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:YES];
                
                // 在sortDescriptorKeys数组中添加一个NSSortDescriptor元素
                [sortDescriptorKeys addObject:sortDescriptor];
            }
            
            // 查询请求设置排序方式
            [fetchRequest setSortDescriptors:sortDescriptorKeys];
        }
        
        // 使用数组来接收查询到的内容
        NSArray * fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
        
        // 如果数组为nil
        if (fetchedObjects == nil) {
            
            // 创建一个新的数组返回, 在外部去做判断
            fetchedObjects = [NSArray new];
        }
        // 返回查找到的数组
        return fetchedObjects;
    }
    
    - (void)deleteAllManagedObjectModels:(NSArray *)models {
        
        // 遍历删除传进来数组中的元素对应的表内容
        for (NSManagedObject * object in models) {
            
            // 使用管理者删除对象, 数组中的元素并没有缺少
            [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
    

    相关文章

      网友评论

          本文标题:iOS项目拆分:数据本地持久化(4)

          本文链接:https://www.haomeiwen.com/subject/ksojuttx.html