天天看点

iOS开发之Core Data数据存储

Core Data是iOS5之后才出现的一个框架,它提供了对象-关系映射(ORM)的功能即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象。

传统的数据库要把数据写到数据库,而且要写SQL语句 Core Data 就避免了写SQL语句的麻烦了

       CoreData底层的持久化存储方式可以是SQLite数据库,也可以是XML文件,甚至可以直接以内存作为持久化存储设备(如果选用该存储方式,那么应用重启时数据会丢失)。

       CoreData的核心概念是实体。实体是由Core Data管理的模型对象,它必须是NSManagedObject类或其子类的实例。实体与实体之间存在1-1、1-N、N-N的关联关系。整个应用的所有实体以及实体之间的关联关系被称为托管对象模型。

       CoreData的核心对象是托管对象上下文(NSManagedObjectContext,有时简称上下文),所有实体都处于托管对象上下文管理中,Core Data应用对实体所做的任何增、删、改、查操作都必须通过托管对象上下文来完成。

       NSManagedObjectContext底层又与持久化存储协调器(NSPersistentStoreCoordinator)衔接。持久化存储协调器负责管理底层的存储形式,比如利用SQLite存储。

下面来总结Core Data中的核心API:

1.    实体(NSManagedObject):代表实体。实体必须是该类或该类的子类

2.    托管对象模型(NSManagedObjectModel):该对象负责管理整个应用的所有实体以及实体之间的关联关系。

3.    持久化存储协调器(NSpersistentStoreCoordinator):负责管理底层的存储方式,如利用SQLite存储。

4.    托管对象上下文(NSManagedObjectContext):对实体做的增、删、改、查操作都必须通过托管对象上下文来完成。

5.    实体描述(NSEntityDescription):该对象代表了关于某个实体的描述信息。从某种角度来说,该对象相当于实体的抽象。

6.    获取请求(NSfetchRequest):该对象封装了查询实体的请求,包括程序需要查询哪些实体、查询条件、排序规则等。

下面介绍一下使用Core Data的步骤:

1.    创建NSManageObjectModel对象来加载管理应用的托管对象模型。

2.    以NSManageObjectModel对象为基础,根据实际创建NSPersistentStoreCoordinator对象,该对象确定Core Data的底层存储形式。

3.    以NSManageObjectModel对象为基础,创建NSmanagedObjectContext对象,该对象是Core Data进行持久化访问的核心对象。

4.    利用获取实例(NSFectRequest)再调用NSmanagedObjectContext的executeFetchRequest:error:方法执行查询,找到符合条件的实体,再进行执行增、删、改、查操作,然后调用NSmanagedObjectContext对象的save:方法将修改白村到底层存储设备。

下面我们还是来通过存储学生信息为例,来讲解CoreData的简单使用。

新建项目,勾选Use Core Data复选框,我这里的项目名为:01-CoreData

iOS开发之Core Data数据存储

create之后,会在项目导航区看到下图文件

iOS开发之Core Data数据存储

还会在appDelegate类中发现多了几个属性和方法,如下:

appDelegate.h

#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;
/**
 *  获取Document的URL路径
 */
- (NSURL *)applicationDocumentsDirectory;
@end
           

appDelegate.m

#pragma mark - Core Data stack

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;


/**
 *  获取Document的URL路径
 */
- (NSURL *)applicationDocumentsDirectory {
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

/**
 *  初始化托管对象模型(实体以及实体之间的关联关系)
 */
- (NSManagedObjectModel *)managedObjectModel {
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    // 获取实体模型文件对应的URL
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"_1_CoreData" withExtension:@"momd"];
    // 根据URL创建并初始化托管模型对象
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

/**
 *  初始化持久化存储协调器(Core Data底层的存储形式)
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    
    // 以托管模型对象创建并初始化协调器
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    
    // 获取SQlLite数据库的存储目录
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"_1_CoreData.sqlite"];
    
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    // 设置底层数据存储机制为SQLite数据库,如果设置失败则返回错误信息
    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];
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    
    return _persistentStoreCoordinator;
}

/**
 *  初始化托管对象上下文
 */
- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }
    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [_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]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}
           

并且在应用的代理方法中有:(当应用退出后,会保存上下文的修改)

- (void)applicationWillTerminate:(UIApplication *)application {
    // Saves changes in the application's managed object context before the application terminates.
    [self saveContext];
}
           

点击.xcodemodeld文件,在工作区会出现如图所示界面

iOS开发之Core Data数据存储

点击左下角add Entity按钮添加实体

iOS开发之Core Data数据存储

然后在ENTITIES区会出现如图所示实体,再重命名实体名,我这里重命名为:StudentEntity

iOS开发之Core Data数据存储

在该实体的右侧会出现添加属性界面,点击添加属性

iOS开发之Core Data数据存储

属性添加完之后,点击xcode导航栏上的Editor -> Create NSManageObject Subclass自动创建实体类,如下:

iOS开发之Core Data数据存储

这些准备工作做好以后,我们就可以向数据库_1_CoreData.sqlite中进行数据的增、删、该、查操作了。

添加学生信息:

iOS开发之Core Data数据存储

点击添加按钮,将学生信息插入数据库中(这里不考虑重复插入)

/**
 *  添加学生信息
 */
- (IBAction)addClick {
    
    // 利用NSEntityDescription获取StudentEntity实体
    StudentEntity *stu = [NSEntityDescription insertNewObjectForEntityForName:@"StudentEntity" inManagedObjectContext:[AppDelegate shareAppDelegate].managedObjectContext];
    stu.name = self.nameTextField.text;
    stu.age = [NSNumber numberWithInteger:[self.ageTextField.text integerValue]];
    stu.sex = [NSNumber numberWithInt:[self.sexTextField.text intValue]];
    
    NSError *error = nil;
    [[AppDelegate shareAppDelegate].managedObjectContext save:&error];
    if (error) {
        NSLog(@"添加失败");
    }else {
        NSLog(@"添加成功");
    }
}
           

点击添加按钮后,会在应用沙盒中发现下图文件:

iOS开发之Core Data数据存储

打印结果:

iOS开发之Core Data数据存储

现在我们向数据库中多插入几条数据,然后来做查询操作,看看数据库中有没有数据。查询操作如下:

/**
 *  查询所有学生信息,并打印
 */
- (IBAction)queryClick {
    // 得到获取数据的请求对象
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
    // 排序规则(查询结果按年龄降序排序)
    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
    request.sortDescriptors = @[sort];
    
    // 执行查询
    NSError *error = nil;// 错误信息
    NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
    if (error) {
        NSLog(@"查询操作失败");
    }else {
        if (result.count <= 0) {
            NSLog(@"无学习信息");
        }else {
            NSLog(@"打印学生信息:");
            for (StudentEntity *stu in result) {
                NSLog(@"姓名:%@,年龄:%lu,性别:%d", stu.name, stu.age.integerValue, stu.sex.intValue);
            }
        }
    }
}
           

打印出来看看,我们刚刚添加的多条学生信息

iOS开发之Core Data数据存储

结果就是我们添加的学生,证明我们的数据已经添加到数据库中了。

我们先来删除指定姓名(如:shx1)的学生信息:(数据库中所有叫shx1的学生会全部删除)

iOS开发之Core Data数据存储
/**
 *  删除指定姓名的学生信息
 */
- (IBAction)deleteClick {
    // 先遍历数据库,查询有无该学生信息,无该学生则不用执行删除操作
    
    // 得到获取数据的请求对象
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
    // 查询条件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", self.deleteNameTextField.text];
    request.predicate = predicate;
    // 排序规则(按年龄升序)
    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
    request.sortDescriptors = @[sort];
    // 执行查询
    NSError *error = nil;// 错误信息
    NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
    // 查询结果
    if (error) {
        NSLog(@"查询操作失败");
    }else {
        if (result.count) {// 有该学生信息,可执行删除操作
            for (StudentEntity *stu in result) {
                // 删除学生信息
                [[AppDelegate shareAppDelegate].managedObjectContext deleteObject:stu];
                NSLog(@"删除成功");
                
            }
            // 删除数据后,保存
            NSError *saveError = nil;
            [[AppDelegate shareAppDelegate].managedObjectContext save:&saveError];
            if (saveError) {
                NSLog(@"删除,保存失败");
            }else {
                NSLog(@"删除,保存成功");
            }
        }else {
            NSLog(@"无该学生信息");
        }
    }
}
           

输入要删除的学生姓名:shx1打印结果:

iOS开发之Core Data数据存储

我们再查询所有学生信息,并打印,看看shx1还在不在,点击查询:

iOS开发之Core Data数据存储

姓名叫shx1的学生没有了,证明我们已经删除了。

现在我们来修改某个学生(比如:shx5)的年龄。(原shx5的年龄从上面指定为22,现在我们将他的年龄改为100,数据库中所有叫shx5的学生的年龄都会被改成100)。

iOS开发之Core Data数据存储
/**
 *  修改某个学生的年龄
 */
- (IBAction)tureClick {
    // 先遍历数据库,查询有无该学生信息,无该学生则不能修改年龄
    
    // 得到获取数据的请求对象
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
    // 查询条件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", self.updateNameTextField.text];
    request.predicate = predicate;
    // 执行查询
    NSError *error = nil;// 错误信息
    NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
    // 查询结果
    if (error) {
        NSLog(@"查询操作失败");
    }else {
        if (result.count) {// 有该学生信息,可执行修改操作
            for (StudentEntity *stu in result) {
                // 修改学生信息
                stu.age = [NSNumber numberWithInt:self.updateAgeTextField.text.intValue];
                NSLog(@"修改成功");
                
            }
            // 删除数据后,保存
            NSError *saveError = nil;
            [[AppDelegate shareAppDelegate].managedObjectContext save:&saveError];
            if (saveError) {
                NSLog(@"修改,保存失败");
            }else {
                NSLog(@"修改,保存成功");
            }
        }else {
            NSLog(@"无该学生信息");
        }
    }
}
           

姓名输入shx5,年龄输入100,打印结果:

iOS开发之Core Data数据存储

我们查询所有的学生信息,并打印出来,看看shx5的年龄是不是100。

iOS开发之Core Data数据存储

姓名叫shx5的学生的年龄已经改为100了,证明我们的数据库操作是正确的。

以上是关于Core Data的简单使用,更进一步的使用我也在学习中。