zoukankan      html  css  js  c++  java
  • CoreData详解与使用

    iOS教程:Core Data数据持久性存储详解

    就像我一直说的,Core Data是iOS编程,乃至Mac编程中使用持久性数据存储的最佳方式,本质上来说,Core Data使用的就是SQLite,但是通过一系列特性避免了使用SQL的一些列的麻烦,不仅如此,他还能够合理管理内存,反正好处很多,我们推荐使用,下面我们先对比它与其他数据持久化方式的优缺点。

      1,它允许按照实体-属性-值模型组织数据,并以XML二进制文件SQLite数据文件的格式将其序列化,简单的说就是封装了我们将对象储存的系列化和取出来的反序列化;

      2,除了为属性整合KVC和KVO的访问方法外, Core Data还整合了适当的集合访问方法来处理多值关系。

      3,Core Data中的managed object扩展了标准的KVC 验证方法,以保证单个的数值在可接受的范围之内,从而使组合的值有意义。

      4, 自动支持对象存储在外部数据仓库的功能。

      5.Core Data 内置了版本跟踪和乐观锁定(optimistic locking)来支持多用户写入冲突的解决

     废话不多说了,使用CoreData的时候要注意线程安全主要是context,不要同时操作一个context,而对于数据连接器内部已经做了线程安全保护。那么下面我们直接来上一份代码,在创建项目的时候选中User Core Data,如下图

      

    在创建工程的时候我们直接勾选Use Core Data,这样我们会在appdelegate里面看到如下

    //
    //  AppDelegate.h
    //  coreData_test
    //
    //  Created by 邹浩 on 15/4/9.
    //  Copyright (c) 2015年 蓝鸥. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    
    @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; //上下文
    @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; //数据模型器
    @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;//数据连接器
    
    - (void)saveContext;//保存,将上下文同步到数据库
    - (NSURL *)applicationDocumentsDirectory;//获取沙河路径
    
    
    @end

    .m里面多了这些东西

    //
    //  AppDelegate.m
    //  coreData_test
    //
    //  Created by 邹浩 on 15/4/9.
    //  Copyright (c) 2015年 蓝鸥. All rights reserved.
    //
    
    #import "AppDelegate.h"
    
    @interface AppDelegate ()
    
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        return YES;
    }
    
    - (void)applicationWillResignActive:(UIApplication *)application {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }
    
    - (void)applicationDidEnterBackground:(UIApplication *)application {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }
    
    - (void)applicationWillEnterForeground:(UIApplication *)application {
        // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    }
    
    - (void)applicationDidBecomeActive:(UIApplication *)application {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }
    
    - (void)applicationWillTerminate:(UIApplication *)application {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        // Saves changes in the application's managed object context before the application terminates.
        [self saveContext];
    }
    
    #pragma mark - Core Data stack
    
    @synthesize managedObjectContext = _managedObjectContext;
    @synthesize managedObjectModel = _managedObjectModel;
    @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
    
    //获取数据库的路径
    - (NSURL *)applicationDocumentsDirectory {
        // The directory the application uses to store the Core Data store file. This code uses a directory named "lanou3g.coreData_test" in the application's documents directory.
        return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    }
    
    //数据模型器的getter方法。懒加载
    - (NSManagedObjectModel *)managedObjectModel {
        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
        if (_managedObjectModel != nil) {
            return _managedObjectModel;
        }
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"coreData_test" withExtension:@"momd"];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];//根据路径创建一个数据模型器
        return _managedObjectModel;
    }
    
    //数据管理器的getter方法。懒加载
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
        if (_persistentStoreCoordinator != nil) {
            return _persistentStoreCoordinator;
        }
        
        // Create the coordinator and store
        
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];//根据数据模型器初始化一个数据管理器
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"coreData_test.sqlite"];//获取数据库路径
        NSError *error = nil;
        NSString *failureReason = @"There was an error creating or loading the application's saved data.";
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {//说明数据管理器管理的数据库
            // Report any error we got.
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
            dict[NSLocalizedFailureReasonErrorKey] = failureReason;
            dict[NSUnderlyingErrorKey] = error;
            error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
            // Replace this 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();
        }
        
        return _persistentStoreCoordinator;
    }
    
    //重写上下文的getter方法,懒加载
    - (NSManagedObjectContext *)managedObjectContext {
        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
        if (_managedObjectContext != nil) {
            return _managedObjectContext;
        }
        
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];//调用数据管理器的getter方法
        if (!coordinator) {
            return nil;
        }
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];//给上下文对象一个数据管理器
        return _managedObjectContext;
    }
    
    #pragma mark - Core Data Saving support
    
    - (void)saveContext {
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            NSError *error = nil;
            if ([managedObjectContext hasChanges] && ![managedObjectContext 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();//相当于断言,只是断言是如果表达式为假,则crash并且打印后面的信息,这里是如果走abort函数,应用异常退出,并且抛出异常信息
              
            }
        }
    }
    
    @end

     那么问题来了,我们项目可能是以前的,里面没有添加CoreData,我们是不是在建一个项目,选中Use Core Data 然后将以前项目里面的代码粘贴过来啊。这种做法可选但是不可取,作为一个技术人员,我们得想一个最优解。那么下面第二种方法来了

    2,我们手动去创建CoreData里面的一些工具类,我们发现appdelegate.h里面有一个多了三个属性,这就是我们CoreData里面的几个常用对象managerCont

    managedObjectContext管理上下文,可以理解为一个零时数据库,managerObjectModel数据模型器,persistentStoreCoordinator数据管理器,再看看appdelegate.m里面都实现了几个对象的Get方法,而且还是懒加载,节省内存。下面我们开始手动创建一个单例,实现数据持久化一些管理对象的创建

    //
    //  ManagerContext.h
    //  CoreData
    //
    //  Created by 邹浩 on 15/4/16.
    //  Copyright (c) 2015年 蓝鸥. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    
    @interface ManagerContext : NSObject
    
    @property (nonatomic, strong)NSManagedObjectContext *context; //上下文
    @property (nonatomic, strong)NSManagedObjectModel *model;//数据模型器
    @property (nonatomic, strong)NSPersistentStoreCoordinator *persistentS;//数据连接器
    
    
    + (instancetype)defaultContext; //获取单利对象
    
    
    @end
    //
    //  ManagerContext.m
    //  CoreData
    //
    //  Created by 邹浩 on 15/4/16.
    //  Copyright (c) 2015年 蓝鸥. All rights reserved.
    //
    
    #import "ManagerContext.h"
    
    @implementation ManagerContext
    
    #pragma mark 获取单利对象
    + (instancetype)defaultContext
    {
        static ManagerContext *manager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            manager = [[ManagerContext alloc] init];
        });
        return manager;
    }
    
    #pragma mark 上下文的懒加载方法,getter方法
    - (NSManagedObjectContext *)context
    {
        if (_context != nil) {
            return _context;
        }
        _context = [[NSManagedObjectContext alloc] init];
        [_context setPersistentStoreCoordinator:self.persistentS];
        return _context;
    }
    #pragma mark 数据连接器的懒加载方法,getter方法
    
    - (NSPersistentStoreCoordinator *)persistentS
    {
        if (_persistentS != nil) {
            return _persistentS;
        }
        _persistentS = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
        NSURL *storeURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"main"];
        NSError *error;
        [_persistentS addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];    return _persistentS;
    }
    
    #pragma mark 数据模型器的懒加载方法,getter方法
    
    - (NSManagedObjectModel *)model
    {
        if (_model != nil) {
            return _model;
        }
        NSURL *url = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"momd"];
        _model = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
        return _model;
    }
    
    
    
    
    @end

    那么剩下的就是获取数据和插入数据了,

    插入数据

     NSManagedObjectContext *context = ((AppDelegate *)[UIApplication sharedApplication].delegate).managedObjectContext;//获取上下文
        NSEntityDescription *StuDE = [NSEntityDescription entityForName:@"StudentClass" inManagedObjectContext:context];//在上下文里面创建描叙文件
        
        StudentClass *stu = [[StudentClass alloc] initWithEntity:StuDE insertIntoManagedObjectContext:context];//根据上下文创建对象并插入到上下文
        
        NSInteger num = [[NSString stringWithFormat:@"%@", self.phoneL.text] integerValue];
        stu.phoneNum = [NSNumber numberWithInteger:num];
        stu.name = self.nameL.text;
        stu.teacher.name = @"zouhao";
        stu.teacher.phoneNum = @13311060923;
        
        NSError *error; // 错误信息
        [context save:&error]; // 把对被管理对象上下文的更改作用到本地文件
        if (!error) {
           
            [self.navigationController popViewControllerAnimated:YES];
    
        }else{
            UIAlertView *alertV = [[UIAlertView alloc] initWithTitle:@"提示" message:@"保存信息失败" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [alertV show];
    
        
        
        
       }

    查找数据

     self.dataArray = [NSMutableArray array];
        
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"ClassEntity"];
        
        NSError *error;
        NSArray *array = [[ManagerContext defaultContext].context executeFetchRequest:request error:&error];
        if (!error) {
            [self.dataArray setArray:array];
    
            [self.tableView reloadData];
        } else {
            UIAlertView *alertV = [[UIAlertView alloc] initWithTitle:@"提示" message:@"取数据失败" delegate:self cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
            [alertV show];
        }

    今天就讲到这里了,后期会继续改进,麻烦大家多多支持

  • 相关阅读:
    进程-线程-消息队列
    用Ogre实现《天龙八部》场景中水面(TerrainLiquid)详解
    TCP协议三次握手过程分析【图解,简单清晰】
    excel批量删除sql语句
    批量删除指定盘指定格式文件
    Linux命令速查手册(第2版)学习
    List、Map、Set 三个接口,存取元素时,各有什么特点
    HashMap 什么时候进行扩容呢
    两个对象值相同 (x.equals(y) == true),但却可有不同的 hash code,这句话对不对?
    ArrayList,Vector, LinkedList 的存储性能和特性
  • 原文地址:https://www.cnblogs.com/zouhaoit/p/4435676.html
Copyright © 2011-2022 走看看