iOS Developer程序员iOS学习笔记

iOS 数据存储

2016-06-23  本文已影响660人  _凉风_

[TOC]

一、应用的文件结构

I. 应用沙盒

II. 应用沙盒的结构

1. 应用程序包

// 获取应用沙盒「应用文佳夹」的文件路径
NSString *homePath = NSHomeDirectory();

2. tmp


// 获取 tmp 文件路径
NSString *tmpPath = NSTemporaryDirectory();

3. Documents

// 获取 Documents 文件路径

// 方法一、利用沙盒根目录拼接 ”Documents” 字符串
// 不建议采用,因为新版本的操作系统可能会修改目录名
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];

// 方法二、利用 NSSearchPathForDirectoriesInDomains 函数
/**
 * @param  NSDocumentDirectory:搜索目录是,Documents 目录
 * @param  NSUserDomainMak:搜索范围是,用户文件夹
 * @param  NO:不展开全路径:~/Library/Caches
 * @return NSArray*
 */
NSArray *array =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
// 在iOS中,只有一个目录跟传入的参数匹配,所以这个集合里面只有一个元素
NSString *documents = [array objectAtIndex:0];

4. Library/Caches

// 获取 Caches 文件路径
// 方法和 获取 Document 文件路径 方法一致
// NSCachesDirectory:搜索目录是 caches 目录
NSArray* array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, NO);
NSString *caches = [array objectAtIndex:0];

5. Library/Preference

// 获取 Preference 文件路径
// 通过 NSUserDefaults类 存取该目录下的 设置信息,这里以用户标准设置信息为例
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

二、iOS应用数据存储常用方式

1. Perference「偏好设置」

简介

示例

// 拿到 standardUserDefaults方法的单例对象
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@"Data" forKey:@"Key"];
[userDefaults setBool:YES forKey:@"Key2"];

// iOS7 之前,以上内容存储在缓存「定时存储」中,现在会自动同步到硬盘中
// iOS7 之前,不会立刻和硬盘同步,要添加一下同步代码「防止调用了set方法后数据还没写入磁盘,应用程序就终止了」
[userDefaults synchronize];
NSString *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"Key"];

2. XML「属性列表」

简介

示例

// 0. 数据源 数组集合
NSArray *arr = @[@"123",@96];
// 1. 获取存放路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains (NSCachesDirectory,NSUserDomainMask,YES)[0];
// 2. 拼接完整路径「全路径」
NSString *filePath = [cachePath stringByAppendingPathComponent:@"arr.plist"];
// 3. 存储「File: 文件全路径」
[arr writeToFile:filePath atomically:YES];
// 1. 获取存放路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains (NSCachesDirectory,NSUserDomainMak,YES)[0];
// 2. 拼接完整路径「全路径」
NSString *filePath = [cachePath stringByAppendingPathComponent:@"arr.plist"];
// 3. 取出文件「由于之前存的是数组集合,所以取的时候也是数组集合」
NSArray *arr = [NSArray arrayWithContentOfFile:filePath];

3. NSKeyedArchiver「归档存储」

简介

示例

@implementation Person
// 存
// 调用:自定义对象 归档的时候 调用
// 作用:说明自定义对象有哪些属性需要 归档
- (void)encoderWithCoder:(NSCoder *)aCoder{
    [super encoderWithCoder:aCoder]; // 如果 父类 使用了 encoderWithCoder 方法的话
    [aCoder encoderObject:_name forKey:@"name"];
    [aCoder encoderInt:_age forKey:@"age"];
}

// 取
// 调用:自定义对象解档的时候调用
// 作用:解析文件
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    // 只要父类遵守了 NSCoding 协议,就调用 父类的 initWithCoder,先初始化父类 self = [super initWithCoder: aDecoder];

    // 这里 super == NSObject,NSObject 并没有遵守 NSCoding协议
    // 具体 initWithFrame 和 initWithCoder 的区别,见 01 UI上
    if (self = [super init]){
        // 注意:一定要给成员变量赋值
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeIntForKey:@"age"];    
    }
    return self;
}
@end
// 自定义对象
Person *person = [[Persong alloc] init];

// 1. 获取存放路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains (NSCachesDirectory,NSUserDomainMak,YES)[0];
// 2. 拼接完整路径「全路径」
NSString *filePath = [cachePath stringByAppendingPathComponent:@"person.data"]; // 后缀名随便取名字
// 3. 把自定义对象 归档
[NSKeyedArchiver archiveRootObject:person toFile:filePath];
// 1. 获取存放路径
NSString *cachePath = NSSearchPathForDirectoriesInDomains (NSCachesDirectory,NSUserDomainMak,YES)[0];
// 2. 拼接完整路径「全路径」
NSString *filePath = [cachePath stringByAppendingPathComponent:@"person.data"]; 
// 3. 把自定义对象 解档
Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

4. NSData

简介

示例

// 新建一块可变数据区

NSMutableData *data = [NSMutableData data];

// 将数据区连接到一个 NSKeyedArchiver 对象

NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];

// 开始存档对象,存档的数据都会存储到 NSMutableData 中

[archiver encodeObject:person1 forKey:@"person1"];

[archiver encodeObject:person2 forKey:@"person2"];

// 存档完毕「一定要调用这个方法」

[archiver finishEncoding];

// 将存档的数据写入文件

[data writeToFile:path atomically:YES];
// 从文件中读取数据

NSData *data = [NSData dataWithContentsOfFile:path];

// 根据数据,解析成一个NSKeyedUnarchiver对象

NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

Person *person1 = [unarchiver decodeObjectForKey:@"person1"];

Person *person2 = [unarchiver decodeObjectForKey:@"person2"];

// 恢复完毕

[unarchiver finishDecoding];
// 临时存储person1的数据

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];

// 解析data,生成一个新的Person对象

Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];

// 分别打印内存地址

NSLog(@"person1:0x%x", person1);

NSLog(@"person2:0x%x", person2);

5. SQLite3「数据库文件」

I. 数据库简介

定义:按照数据结构来组织、存储和管理的仓库
分类

数据类型: blob real integer text null
解释: 二进制 浮点数/实数 整数 文本字符串

支持的数据类型:数据库本质不区分类型,只是方便程序员沟通

数据类型: blob real integer text null
解释: 二进制 浮点数/实数 整数 文本字符串

0)数据库的结构

表「tables」:可以有多个

1)主键约束「Primary Key,简称PK」

定义

主键的设计原则

2)外键约束「Foreign Key,简称FK」

II. SQL 语句的分类

简介:SQL「structured query language」结构化查询语言,不区分大小写
规范:SQL 关键字 大写

1)数据定义语句「DDL:Data Definition Language」

/*只有 多行注释
一般格式,如果表存在,重复执行会报错*/
create table 表名 (字段名1 字段类型1, 字段名2 字段类型2, …);

/*如果不存在,就创建表;如果存在,则 不创建
防止重复创建表,覆盖原来表的数据*/ 
create table if not exists 表名 (id integer, name text, primary key(id)); /*这里的 id 被设为主键,但无法自增长*/

/*删除表,如果表不存在,重复执行会报错*/
drop table 表名;
/*删除表 完整的写法*/
drop table if exists 表名;
/*id 设置为主键,且设定 id 自增长「自增长的 id类型必须是 integer」*/
create table if not exists 表名 (id integer primary key autoincrement, name text);

create table T_student (
    id integer primary key autoincrement, /*主键默认有 not null unique 约束,*/
    name text not null unique,     /*name字段 不能为null,且 唯一*/
    age integer not null default 1 /*age字段 不能为null,且 默认为1*/
);
/* t_student 表中 有一个叫做 fk_t_student_class_id_t_class_id 的外键
这个外键的作用: 用 t_student 表中的 class_id字段 引用 t_class表的id字段 */

CREATE TABLE IF NOT EXISTS t_student (
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    name TEXT, 
    age INTEGER, 
    class_id INTEGER, 
    CONSTRAINT fk_t_student_class_id_t_class_id FOREIGN KEY (class_id) REFERENCES t_class (id)
); 

2)数据操作语句「DML:Data Manipulation Language」

/*插入数据 
注:数据库 字符串内容用 ' 括起来「虽然 " 不会报错」
重复插入不会报错,会插入多个相同的数据*/
insert into 表名(字段1, 字段2, ...) values (字段1的值, 字段2的值, ...);

/*更新数据
没有说明具体哪条记录,所有字段1、2的值都会更新*/
update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值; 

/*删除数据
没有说明具体那条记录,会删除表中所有的记录*/
delete from 表名;
where 字段 = 某个值;  /*判断是否为 某个数,= 是等于*/
where 字段 is 某个值; /*判断是否为 某个数,is 是等于*/
where 字段 != 某个值;      /*判断是否不为 某个数*/
where 字段 is not 某个值;  /*判断是否不为 某个数,is not 是不等于*/
where 字段 > 某个值; 
where 字段1 = 某个值 and 字段2 > 某个值;  /* and相当于C语言中的 && */
where 字段1 = 某个值 or 字段2 = 某个值;   /* or 相当于C语言中的 || */
/*格式*/
update 表名 set 字段1=属性1, 字段2=属性2 where 依据字段1=依据字段1的值;

/*示例*/
/*1. 删除t_student表中年龄小于等于10 或者 年龄大于30的记录*/
delete from t_student where age <= 10 or age > 30 ;
/*2. 将t_student表中名字等于jack的记录,score字段的值 都改为 age字段的值*/

update t_student set score = age where name = ‘jack’ ;

3)数据查询语句「DQL:Data Query Language」

/*格式*/
select 字段1, 字段2, … from 表名;
select * from 表名; /*查询所有的字段*/

/*示例,查询所有 age>10 的记录*/
select * from T_tableName where age>10; 
/*格式, 下面3行代码作用相同,格式不同*/
select 字段1 别名, 字段2 别名, … from 表名 别名; 
select 字段1 as 别名, 字段2 as 别名, … from 表名 as 别名;
select 别名.字段1, 别名.字段2, … from 表名 别名;

/*示例*/
/*name起别名为ThisName, age起别名为ThisAge*/
select name ThisName, age ThisAge from T_student;
/*T_student表起个别名叫做s,利用s来引用表中的字段*/
select s.name, s.age, t.name, t.age from T_student s, T_teacher t;
select count (字段) from 表名; /*count() 查询指定内容有多少条记录*/

select * from 表名 order by 字段1; /*根据 字段1将查出的记录排序,默认升序「由小到大」*/
select * from T_student order by age desc; /* 降序 */
select * from T_student order by age asc;  /* 升序 */

/*先 按年龄排序(升序),年龄相等 就按 身高排序(降序)*/
select * from T_student order by age asc,height desc ;
/* 格式1:limit 数值1, 数值2
   数值1:跳过几条记录
   数值2:读取几条记录 */

select * from T_student limit 4, 8; /*跳过最前面4条语句,取8条记录*/

/*格式2:limit 取前几条数据的个数*/

select * from T_student limit 7; /* 取最前面的7条记录,相当于 select * from T_student limit 0, 7; */

内连接:inner join 或者 join 「显示的是左右表都有完整字段值的记录」
左外连接:left outer join「保证左表数据的完整性」

/* 普通查询方式 */
select s.name,s.age from T_student s, T_class c where s.class_id = c.id and c.name = 'iOSClass';
/* 内连接查询方式,这里的 on 相当与 where,inner join 和 ,效果一样*/
select s.name,s.age from T_student s inner join T_class c on s.class_id = c.id;
/* 不使用连接的查询方式,嵌套查询 */
select s.name from T_student s where s.class_id = (select c.id from T_class c where c.name = 'iOSClass');

4)模糊查询

模糊查询 like 的使用格式

通配符

  1. %:代替 任意0个或多个 字符
  1. _:代替 任意单个 字符
  1. []:代替括号内所列字符中的一个「类似正则表达式」
  1. [^]:代替不在括号所列之内的单个字符
  1. 查询内容包含通配符时
  1. 通配符的综合使用

5)事务操作

事务

注意:

示例

// 1. 开启事务
begin transaction;
// 2. 数据库其他操作
// 3. 回滚事务「主动的操作」
rollback transaction;
// 4. 提交事务
commit transaction;

III. SQLite

简介

注意

1)创建或打开数据库

// path:数据库文件的存放路径「必须是 C 语言字符串(而非 NSString )」
sqlite3 *db = NULL; // 指针 db 指向一个打开的数据库实例对象

// 如果 result 等于常量 SQLITE_OK,则表示成功打开数据库
//「注:result 是 int 类型,这里有许多 int 类型的数字常量标记状态,在这里写程序时应避免」
int result = sqlite3_open([path UTF8String], &db); 

sqlite3_close(db); // 关闭数据库「有开就有关」

2)不返回数据的 sqlite3_exec() 函数

// 凡是传地址的指针提前置为 NULL 防止野指针出现
char *errorMsg = NULL;  // errorMsg:存储错误信息
// sql:想要执行的 SQL 语句「C 语言字符串」
char *sql = "create table if not exists t_person(id integer primary key autoincrement, name text, age integer);";
// result 返回执行是否成功的状态
int result = sqlite3_exec(db, sql, NULL, NULL, &errorMsg);

SQlite 的事务处理语句

3)预编译绑定

优点

// ? 是占位符,在占位符号替换真实数据时会进行安全检测,防止 SQL 注入
char *sql = "insert into t_person(name, age) values(?, ?);";
sqlite3_stmt *stmt; // 存放结果集

// sqlite3_prepare_v2()返回值 == SQLITE_OK,说明SQL语句已经准备成功,没有语法问题
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
    /* sqlite3_bind_text():大部分绑定函数都只有3个参数
    参数1:sqlite3_stmt *类型
    参数2:占位符的位置,第一个占位符的位置是 1,不是 0
    参数3:占位符要绑定的值
    参数4:在参数3中所传递数据的长度,对于 C 字符串,可以传递 -1 代替字符串的长度
    参数5:一个可选的函数回调,一般用于在语句执行后完成内存清理工作 */
    sqlite3_bind_text(stmt, 1, "母鸡", -1, NULL); // 将真实值绑定所选的位置上,防止SQL注入
    sqlite3_bind_int(stmt, 2, 27);
}

// sqlite3_step():执行SQL语句,返回 SQLITE_DONE 代表 成功执行完毕
if (sqlite3_step(stmt) != SQLITE_DONE) {
    NSLog(@"插入数据错误");
}

// sqlite3_finalize():销毁sqlite3_stmt *对象
sqlite3_finalize(stmt); 

4)查询数据

sqlite3_stmt *stmt;
char *sql = "select id,name,age from t_person;";
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
    while (sqlite3_step(stmt) == SQLITE_ROW) {  // sqlite3_step():返回SQLITE_ROW代表遍历到一条新记录
        int _id = sqlite3_column_int(stmt, 0);  // sqlite3_column_*():获取每个字段对应的值
        int _age = sqlite3_column_int(stmt, 2); // 参数2对应上面 sql 字段的索引「从0开始」
        char *_name = (char *)sqlite3_column_text(stmt, 1);
        NSString *name = [NSString stringWithUTF8String:_name];
    }
}

sqlite3_finalize(stmt);

IV. FMDB 框架

简介

核心类简介

1)打开数据库

通过指定 SQLite 数据库文件路径来创建 FMDatabase 对象

FMDatabase *db = [FMDatabase databaseWithPath:path];
if (![db open]) {
    NSLog(@"数据库打开失败!");
}

以上代码的文件路径 path 有三种情况

2)更新数据库

在 FMDB 中,除查询以外 的所有操作「create、drop、insert、update、delete等」,都称为“更新”

// 使用executeUpdate:方法执行更新,返回的 BOOL 值表示是否执行成功
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments

示例

// 1. 从 doc 里获得文件路径
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"];
// 2. 创建数据库
FMDatabase *db = [FMDatabase databaseWithPath:path];
// 3. 打开数据库
if (![db open]) {
 NSLog(@"数据库打开失败!");
}
// 4. 在数据库中创建表
[db executeUpdate:@"create table if not exists t_student (id integer primary key autoincrement, name text, age integer);"];
// 5. 数据库内容更新
[db executeUpdate:@"insert into t_student (name, age) values (?, ?);", name, age];
[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"];
// 6. 使用完后关闭数据库
[db close];

3)查询数据库

查询方法

- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments

示例

// 查询数据
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student"];
// 遍历结果集
while ([rs next]) {
    NSString *name = [rs stringForColumn:@"name"];
    int age = [rs intForColumn:@"age"];
    double score = [rs doubleForColumn:@"score"];
}

4)事务处理

5)FMDatabaseQueue

FMDatabaseQueue 的创建

// 1. 从 doc 里获得文件路径
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"];
// 2. 创建数据库队列
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];

FMDatabaseQueue 的数据库安全调用

[queue inDatabase:^(FMDatabase *db) {
    // 传入的只是一个打开的数据库,仍需要创表
    [db executeUpdate:@"create table if not exists t_student (id integer primary key autoincrement, name text, age integer);"];
    // 更新数据库的其他操作
    [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
}];

// 事务使用
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    [db executeUpdate:@"INSERT INTO t_student(name) VALUES (?)", @"Jack"];
    // 事务回滚
    *rollback = YES;
}];

6. Core Data 框架

简介

提供对象-关系映射「Object-relationalmaping(O/RM)」的功能,即能够将 OC对象 转化成 数据,保存在 SQLite3 数据库文件中
也能够将保存在数据库中的数据 还原成 OC对象

特点

I. 模型文件「Data Model」

简介

映射关系

II. NSManagedObject

III. 主要对象

NSManagedObjectContext:被管理的上下文,负责应用和数据库之间的交互「CRUD」

IV. 开发步骤

0)创建模型文件

  1. 例子 模型文件


  2. 选择模板




  3. 添加实体


  4. 添加 Person 属性
  1. 添加 Card 属性


  2. 建立 Person 和 Card 的关系
    • Person 中 添加 Card 属性



    • Card 中添加 Person 属性


    • 下图中的表示 Card 中有个 Person 类型的 person属性

      目的就是建立 Card 跟 Person 之间的一对一关联关系「建议补上这一项」
      在 Person 中加上 Inverse 属性后,会发现 Card 中 Inverse 属性也自动补上了

1)搭建 Core Data 上下文环境

// 1. 从应用程序包中加载模型文件,读取 app 中的所有实体信息
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];

// 2. 传入模型,初始化 NSPersistentStoreCoordinator
NSPersistentStoreCoordinator *psc = [[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model] autorelease];

// 3. 构建 SQLite 文件路径
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *url = [NSURL fileURLWithPath:[docs stringByAppendingPathComponent:@"person.data"]];

// 4. 添加持久化存储库,这里使用SQLite作为存储库
NSError *error = nil;
NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
if (store == nil) { // 直接抛异常
    [NSException raise:@"添加数据库错误" format:@"%@", [error localizedDescription]];
}

// 5. 初始化 NSManagedObjectContext 上下文,设置 persistentStoreCoordinator 属性
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
context.persistentStoreCoordinator = psc;

// 6. 上下文不用后,要及时释放掉
[context release];

2)添加数据


// 1. 传入上下文,创建一个Person实体对象  
NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];  

// 2. 设置Person的简单属性  
[person setValue:@"SunFarrell" forKey:@"name"];  
[person setValue:[NSNumber numberWithInt:23] forKey:@"age"];  
//    传入上下文,创建一个Card实体对象  
NSManagedObject *card = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:context];  
[card setValue:@"2332332333" forKey:@"no"];  
//    设置Person和Card之间的关联关系  
[person setValue:card forKey:@"card"];  

// 3. 利用上下文对象,将数据同步到持久化存储库  
NSError *error = nil;  
BOOL success = [context save:&error];  
if (!success) {  
    [NSException raise:@"访问数据库错误" format:@"%@", [error localizedDescription]];  
}  

// 4. 更新操作「耗时间」:在更改了实体对象的属性后,将更改的数据同步到数据库
 [context save:&error]; 

3)查询数据

// 1. 初始化一个查询请求
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];

// 2. 设置要查询的实体
request.entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
//    设置排序(按照age降序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:sort];
//    设置条件过滤(搜索name中包含字符串"Itcast-1"的记录
//    注意:设置条件过滤时,数据库SQL语句中的%要用*来代替,所以%Itcast-1%应该写成*Itcast-1*)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*Itcast-1*"];
request.predicate = predicate;

// 3. 执行请求
NSError *error = nil;
NSArray *objs = [context executeFetchRequest:request error:&error];
if (error) {
    [NSException raise:@"查询错误" format:@"%@", [error localizedDescription]];
}

// 4. 遍历数据
for (NSManagedObject *obj in objs) {
    NSLog(@"name=%@", [obj valueForKey:@"name"]
}

4)删除数据

// 1. 传入需要删除的实体对象
[context deleteObject:managedObject];

// 2. 将结果同步到数据库
NSError *error = nil;
[context save:&error];
if (error) {
    [NSException raise:@"删除错误" format:@"%@", [error localizedDescription]];
}

V. 打开 CoreData 的 SQL 语句输出开关

1 打开Product,点击 EditScheme


2 点击 Arguments,在 ArgumentsPassed On Launch 中添加2项

VI. 创建 NSManagedObject 的子类

默认的,用 Core Data 取出的实体都是 NSManagedObject 类型,能用 键-值对 来存取数据
但一般情况下,实体在存取数据的基础上,有时还需要添加一些业务方法来完成一些其他任务,那么就必须创建NSManagedObject 的子类

  1. 选择模型文件


  2. 选择需要创建子类的实体


  3. 创建完毕后多了两个子类


文件内容如下

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

@class Card;

@interface Person : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * age;
@property (nonatomic, retain) Card *card;

@end
#import "Person.h"
@implementation Person

@dynamic name;
@dynamic age;
@dynamic card;

@end
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Person;

@interface Card : NSManagedObject
@property (nonatomic, retain) NSString * no;
@property (nonatomic, retain) Person *person;
@end
#import "Card.h"
#import "Person.h"

@implementation Card
@dynamic no;
@dynamic person;
@end

Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];  
person.name = @"SunFarrell";  
person.age = [NSNumber numberWithInt:23];  
  
card.no = @"23323323333";  
Card *card = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:context]; 
person.card = card;  

// 最后调用 [context save&error]; 保存数据
上一篇 下一篇

猜你喜欢

热点阅读