zoukankan      html  css  js  c++  java
  • iOS: 转载CoreData数据库框架

    iphone-CoreData的使用详解

    一、概念

    1.Core Data 是数据持久化存储的最佳方式

    2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型

    在Mac OS X 10.5Leopard及以后的版本中,开发者也可以通过继承NSPersistentStore类以创建自定义的存储格式

    3.好处:能够合理管理内存,避免使用sql的麻烦,高效

    4.构成:

    (1)NSManagedObjectContext(被管理的数据上下文)

    操作实际内容(操作持久层)

    作用:插入数据,查询数据,删除数据

    (2)NSManagedObjectModel(被管理的数据模型)

    数据库所有表格或数据结构,包含各实体的定义信息

    作用:添加实体的属性,建立属性之间的关系

    操作方法:视图编辑器,或代码

    (3)NSPersistentStoreCoordinator(持久化存储助理)

    相当于数据库的连接器

    作用:设置数据存储的名字,位置,存储方式,和存储时机

    (4)NSManagedObject(被管理的数据记录)

    相当于数据库中的表格记录

    (5)NSFetchRequest(获取数据的请求)

    相当于查询语句

    (6)NSEntityDescription(实体结构)

    相当于表格结构

    (7)后缀为.xcdatamodeld的包

    里面是.xcdatamodel文件,用数据模型编辑器编辑

    编译后为.momd或.mom文件

    5.依赖关系

    二、基于SQLite数据库时,Core Data的简单使用

    和SQLite的区别:只能取出整个实体记录,然后分解,之后才能得到实体的某个属性

    1.构建流程

    包括:创建数据上下文,创建数据模型,创建数据持久化存储助理

    (1)若是新建的工程,选择空白应用程序,next

    勾选Use Core Data选项

    此时生成的工程文件AppDelegate中,会自动生成被管理的数据上下文等相关代码

    (2)比如AppDelegate.h文件中,自动生成

    @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
    @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
    @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
    
    - (void)saveContext;
    - (NSURL *)applicationDocumentsDirectory;

    方法saveContext表示:保存数据到持久层(数据库)

    方法applicationDocumentsDirectory表示:应用程序沙箱下的Documents目录路径

    (例如/var/mobile/Applications/5FG80A45-DFB5-4087-A1B1-41342A977E21/Documents/)

    (3)比如AppDelegate.h文件中,自动生成

    @synthesize managedObjectContext = __managedObjectContext;
    @synthesize managedObjectModel = __managedObjectModel;
    @synthesize persistentStoreCoordinator = __persistentStoreCoordinator;

    保存数据到持久层

    - (void)applicationWillTerminate:(UIApplication *)application
    {
        [self saveContext];
    }
    - (void)saveContext
    {
        NSError *error = nil;
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            } 
        }
    }

    Documents目录路径

    - (NSURL *)applicationDocumentsDirectory
    {
        return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    }

    被管理的数据上下文

    初始化的后,必须设置持久化存储助理

    - (NSManagedObjectContext *)managedObjectContext
    {
        if (__managedObjectContext != nil) {
            return __managedObjectContext;
        }
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (coordinator != nil) {
            __managedObjectContext = [[NSManagedObjectContext alloc] init];
            [__managedObjectContext setPersistentStoreCoordinator:coordinator];
        }
        return __managedObjectContext;
    }

    被管理的数据模型

    初始化必须依赖.momd文件路径,而.momd文件由.xcdatamodeld文件编译而来

    - (NSManagedObjectModel *)managedObjectModel
    {
        if (__managedObjectModel != nil) {
            return __managedObjectModel;
        }
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"TestApp" withExtension:@"momd"];
        __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return __managedObjectModel;
    }

    持久化存储助理

    初始化必须依赖NSManagedObjectModel,之后要指定持久化存储的数据类型,默认的是NSSQLiteStoreType,即SQLite数据库;并指定存储路径为Documents目录下,以及数据库名称

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if (__persistentStoreCoordinator != nil) {
            return __persistentStoreCoordinator;
        }
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"TestApp.sqlite"];
    NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return __persistentStoreCoordinator; }

    如果不是新工程,也可以自己写入相关代码

    (4)此外还生成了TestApp.xcdatamodeld文件

    (5)还自动链接了CoreData.framework

    (6)在预编译头.pch文件中,加入导入了CoreData.h头文件

    #import <CoreData/CoreData.h>

    2.创建数据模型(数据模型编辑器操作)

    (1)创建实体

    选中.xcodedatamodel对象

    在右边的数据模型编辑器的底部工具栏点击Add Entity添加实体

    在最右侧栏对实体命名

    (2)创建实体属性

    选中实体,点击底部工具栏的Add Attribute添加属性

    选中新添加的属性,对属性进行命名,并设置属性的数据类型Attribute Type

    (3)为两个实体建立关系

    选中一个实体,在底部工具栏点击Add Relationship添加关系

    选中新关系,对关系添加名称,目标destination设置为另个实体

    (4)建立返回关系

    (当你建立一个目标关系,最好建立一个返回关系)

    在另一个实体中建立一个关系并命名,设置目标对象为这之前的实体

    并在Inverse属性选这之前的关系名称

    (5)设置两个关系的删除规则Delete Rule,都为关联模式

    关联模式cascade:其中一个数据被删除,另一个实体中的数据也会跟着删除

    (6)最终两个对象的关系图为

    切换Editor Stype按钮

    会看到另一种编辑方式:

     3.插入数据

    在AppDelegate.m的application:didFinishLaunchingWithOptions:方法里,调用自定义方法

    insertCoreData插入数据,代码如下:

    - (void)insertCoreData
    {
        NSManagedObjectContext *context = [self managedObjectContext];
        
        NSManagedObject *contactInfo = [NSEntityDescription insertNewObjectForEntityForName:@"ContactInfo" inManagedObjectContext:context];
        [contactInfo setValue:@"name B" forKey:@"name"];
        [contactInfo setValue:@"birthday B" forKey:@"birthday"];
        [contactInfo setValue:@"age B" forKey:@"age"];
        
        NSManagedObject *contactDetailInfo = [NSEntityDescription insertNewObjectForEntityForName:@"ContactDetailInfo" inManagedObjectContext:context];
        [contactDetailInfo setValue:@"address B" forKey:@"address"];
        [contactDetailInfo setValue:@"name B" forKey:@"name"];
        [contactDetailInfo setValue:@"telephone B" forKey:@"telephone"];
        
        [contactDetailInfo setValue:contactInfo forKey:@"info"];
        [contactInfo setValue:contactDetailInfo forKey:@"details"];
        
        NSError *error;
        if(![context save:&error])
        {
            NSLog(@"不能保存:%@",[error localizedDescription]);
        }
    }

    创建数据上下文,调用insertNewObjectForName方法,创建两个数据记录NSManagedObject,然后就可以对之前数据模型编辑视图中定义的属性进行赋值。此时的数据只在内存中被修改,最后调用数据上下文的save方法,保存到持久层

    4.查询数据

    在调用了insertCoreData之后,可以调用自定的查询方法dataFetchRequest来查询插入的数据

    - (void)dataFetchRequest
    {
        NSManagedObjectContext *context = [self managedObjectContext];
        NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"ContactInfo" inManagedObjectContext:context];
        [fetchRequest setEntity:entity];
        NSError *error;
        NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
        for (NSManagedObject *info in fetchedObjects) {
            NSLog(@"name:%@", [info valueForKey:@"name"]);
            NSLog(@"age:%@", [info valueForKey:@"age"]);
            NSLog(@"birthday:%@", [info valueForKey:@"birthday"]);
            NSManagedObject *details = [info valueForKey:@"details"];
            NSLog(@"address:%@", [details valueForKey:@"address"]);
             NSLog(@"telephone:%@", [details valueForKey:@"telephone"]);
        }
    }

    fetchRequest相当于sql查询语句的包装类,需要用setEntity方法,来指定具体查询的实体结构(表结构)

    通过NSEntityDescription的entityForName方法来,返回指向该具体实体结构的指针

    然后调用executeFetchRequest:error:方法,来执行查询操作,如果操作成功,则返回对应的数据记录数组

    其中,可以通过NSManagedObject数据记录对象里关联的属性,查询另一个数据记录对象里的属性

    5.数据模版

    为每个实体生成一个NSManagedObject子类

    上面设置数据和获取数据时,使用的是Key-Value方式,更好的方法是通过生成强类型的NSManagedObject的子类,通过类的成员属性来访问和获取数据

    (1)在数据编辑器视图中选中实体对象,

    选则file菜单,点击new,点击file...,选择Core Data项,选择NSManagedObject subclass,生成该实体同名的类,

    继承于NSManagedObject

    生成对应的ContactInfo.h文件

    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    
    @class ContactDetailInfo;
    
    @interface ContactInfo : NSManagedObject
    
    @property (nonatomic, retain) NSString * age;
    @property (nonatomic, retain) NSString * birthday;
    @property (nonatomic, retain) NSString * name;
    @property (nonatomic, retain) ContactDetailInfo *details;
    
    @end

    和ContactInfo.m文件

    其中,@dynamic告诉编译器不做处理,使编译通过,其getter和setter方法会在运行时动态创建,由Core Data框架为此类属性生成存取方法

    #import "ContactInfo.h"
    #import "ContactDetailInfo.h"
    
    
    @implementation ContactInfo
    
    @dynamic age;
    @dynamic birthday;
    @dynamic name;
    @dynamic details;
    
    @end

    以及ContactDetailInfo.h文件

    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    
    @class ContactInfo;
    
    @interface ContactDetailInfo : NSManagedObject
    
    @property (nonatomic, retain) NSString * address;
    @property (nonatomic, retain) NSString * name;
    @property (nonatomic, retain) NSString * telephone;
    @property (nonatomic, retain) ContactInfo *info;
    
    @end

    和ContactDetailInfo.m文件

    #import "ContactDetailInfo.h"
    #import "ContactInfo.h"
    
    
    @implementation ContactDetailInfo
    
    @dynamic address;
    @dynamic name;
    @dynamic telephone;
    @dynamic info;
    
    @end

    此时,数据模型编辑器视图最右边栏中,实体的class就变成具体的类名

    之前用Key-Value的代码就可以修改为:

    #import "ContactInfo.h"
    #import "ContactDetailInfo.h"
    - (void)insertCoreData
    {
        NSManagedObjectContext *context = [self managedObjectContext];
        
        ContactInfo *contactInfo = [NSEntityDescription insertNewObjectForEntityForName:@"ContactInfo" inManagedObjectContext:context];
        contactInfo.name = @"name B";
        contactInfo.birthday = @"birthday B";
        contactInfo.age = @"age B";
        
        ContactDetailInfo *contactDetailInfo = [NSEntityDescription insertNewObjectForEntityForName:@"ContactDetailInfo" inManagedObjectContext:context];
        contactDetailInfo.address = @"address B";
        contactDetailInfo.name = @"name B";
        contactDetailInfo.telephone = @"telephone B";
        
        contactDetailInfo.info = contactInfo;
        contactInfo.details = contactDetailInfo;
        
        NSError *error;
        if(![context save:&error])
        {
            NSLog(@"不能保存:%@",[error localizedDescription]);
        }
    }
    - (void)dataFetchRequest
    {
        NSManagedObjectContext *context = [self managedObjectContext];
        NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"ContactInfo" inManagedObjectContext:context];
        [fetchRequest setEntity:entity];
        NSError *error;
        NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
        for (ContactInfo *info in fetchedObjects) {
            
            NSLog(@"name:%@", info.name);
            NSLog(@"age:%@", info.age);
            NSLog(@"birthday:%@", info.birthday);
            ContactDetailInfo *details = info.details;
            NSLog(@"address:%@", details.address);
             NSLog(@"telephone:%@", details.telephone);
        }
    }

    三、数据库相关

    1.打印隐藏的sql语句:

    在Edit Scheme中选择Run,之后进入Arguments标签,添加参数:“-com.apple.CoreData.SQLDebug 1”

    2.使用SQLite存储时,数据库结构

    存储的SQLite数据库表名称:大写“Z”加上实体名称大写,一个实体相当于一张表

    具体的字段名称:大写“Z”加上实体属性名称大写

  • 相关阅读:
    94. Binary Tree Inorder Traversal
    101. Symmetric Tree
    38. Count and Say
    28. Implement strStr()
    实训团队心得(1)
    探索性测试入门
    LC.278. First Bad Version
    Search in Unknown Sized Sorted Array
    LC.88. Merge Sorted Array
    LC.283.Move Zeroes
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/4827224.html
Copyright © 2011-2022 走看看