第三章:iOS的数据存储与IO

如果应用程序值需要保存程序参数、选项相关的少量数据,则可使用NSUserDefaults进行保存;
如果应用程序只是少量数据需要保存,那使用属性列表文件就可以了;
如果应用程序有大量数据需要存储、访问,就需要借助于数据库.iOS系统内置了SQLite数据库,SQLite数据库是一个真正轻量级的数据库,他没有后台进程,整个数据库就对应于一个文件,这样就可以非常方便的在不同设备之间移植.iOS为访问SQLite数据库提供了两套API:基于C语言风格的libsqlite3.dylib和面向对象的Core Data.

一、应用程序沙盒

为了提供更好的安全机制,iOS提供了应用程序沙盒机制,这种机制保证每个应用程序只能访问本沙盒内的数据,避免与其他应用形成冲突.在OS X系统中查看应用沙盒,有两种方式:

  • (1)、打开Finder应用程序,通过”commend+shift+G”快捷键打开”前往文件夹”对话框,用户可以在该对话框中输入”/user/<用户名>/library/“,这样即可进入OS X的库名录.然后依次进入该目录下的Application Support/iPhone Simulator/7.0/Applications子目录(此处是进入iOS模拟器);

注意:Xcode 5和Xcode 6的模拟器路径比较
①、Xcode 5中模拟器路径为:/Users/用户名/Library/Application Support/iPhone Simulator

②、Xcode 6中模拟器路径为:/Users/用户名/ Library/Developer/CoreSimulator

其中Devices文件夹下的16个文件对应Xcode6下的16个模拟器,可以根据各个文件夹下的device.plist文件得到具体的是哪个模拟器:
第三章:iOS的数据存储与IO_第1张图片
第三章:iOS的数据存储与IO_第2张图片
第三章:iOS的数据存储与IO_第3张图片
注意:Xcode 5和Xcode 6的沙盒路径比较
①、Xcode 5中沙盒的路径为:/Users/用户名/Library/Application Support/iPhone Simulator/7.1-64/Applications/对应应用程序文件夹
Document
②、Xcode 6中沙盒的路径为:/Users/用户名/Library/ Developer/CoreSimulator/Devices/模拟器UDID/data/Containers/Bundle/Applications/对应应用程序文件夹
第三章:iOS的数据存储与IO_第4张图片
注意:Xcode 5和Xcode 6的偏好设置目录比较
①、Xcode 5中偏好设置目录的路径为:/Users/用户名/Library/Application Support/iPhone Simulator/7.1-64/Applications/对应应用程序文件夹/Library/Preferences
第三章:iOS的数据存储与IO_第5张图片
②、Xcode 6中偏好设置目录的路径为:使用NSUserDefault方式创建的plist文件的具体路径为:/Users/用户名/Library/ Developer/CoreSimulator/Devices/模拟器UDID/data/Library/Preferences
第三章:iOS的数据存储与IO_第6张图片

  • (2)、在OS X系统命令行窗口输入”defaults write com.apple.finder AppleShowAllFiles -bool true”,然后退出Finder,重启Finder程序即可看到隐藏文件和文件夹,这样就可以直接查找路径.

显示:defaults write com.apple.finder AppleShowAllFiles -bool true

隐藏:defaults write com.apple.finder AppleShowAllFiles -bool false

打开任何应用程序的文件夹,都可以看到如下文件结构:

  • ①、Documents:除了基于NSUserDefaults的首选项设置之外,应用程序的数据、文件都保存在该目录下;
  • ②、Library:基于NSUserDefaults的首选项参数保存在Library/Preferences目录下;
  • ③、tmp:该目录下供应用程序存储临时问文件,当iOS执行同步时,iTunes不回备份tmp目录下得文件.因此当应用程序不在需要某个临时文件时,应该负责删除tmp目录下的临时文件,避免占用系统空间.

1、获取Documents目录

NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
/Users/osx2014/Library/Developer/CoreSimulator/Devices/C99ACFA5-7162-497A-BA7F-0FF93C7F6867/data/Containers/Data/Application/FBFAF7C5-3053-45AA-A1A4-72B98E858A24/Documents

由于NSSearchPathForDirectoriesInDomains()函数并不是专门为iOS设计的,它最初是为了OS X系统设计的,因此在使用该函数的很多选项都不会返回任何值.该函数的第一个参数代表正在查找Documents文件夹,NSUserDomainMask参数代表仅查找当前用户的Home目录.

2、获取tmp目录

NSString* tmpPath = NSTemporaryDirectory();
/Users/osx2014/Library/Developer/CoreSimulator/Devices/C99ACFA5-7162-497A-BA7F-0FF93C7F6867/data/Containers/Data/Application/FBFAF7C5-3053-45AA-A1A4-72B98E858A24/tmp/

3、获取caches目录

NSArray *cachePaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDir = [cachePaths objectAtIndex:0];
/Users/osx2014/Library/Developer/CoreSimulator/Devices/C99ACFA5-7162-497A-BA7F-0FF93C7F6867/data/Containers/Data/Application/BB4C3035-9A66-4DDA-A74B-0B7FC10CC901/Library/Caches

4、获取home目录

NSString* homePaht = NSHomeDirectory();
/Users/osx2014/Library/Developer/CoreSimulator/Devices/C99ACFA5-7162-497A-BA7F-0FF93C7F6867/data/Containers/Data/Application/BB4C3035-9A66-4DDA-A74B-0B7FC10CC901

5、文件保存策略思考

当应用程序需要把运行状态、用户数据保存下来时,通常会选择保存在应用程序沙盒的Documents文件夹下,除了基于NSUserDefaults的数据会保存在Library/Prefereences目录下(Xcode 5),一些应用程序的临时文件会选择保存在tmp目录下—一旦该文件失去作用,应用程序应该立即删除该临时文件,释放手机上宝贵的存储空间.

使用多文件保存数据的优缺点如下:

  • (1)、优点:应用程序需要使用哪部分数据,就加载哪个文件,从而避免一次性加载所有持久化数据带来的内存紧张.应用程序修改了哪部分数据,只要保存对应的文件即可,这样可以避免同时保存所有的持久化数据.
  • (2)、缺点:多文件保存数据必然带来编程的复杂性,可能需要建立额外的数据结构去管理持久化内容与存储文件之间的对应关系.

二、应用程序参数与用户默认设置

应用程序保存少量的数据(字符串、标量类型等),比如应用程序的各种配置信息(如是打开音效,是否使用振动效果等)、游戏的玩家信息(用户名,密码之类的)等,iOS提供了Settings Bundle来管理.

1、使用Settings Bundle

使用Settings Bundle设置应用程序参数的最大优势在于:无须程序员开发界面,应用的设置界面完全由Setting应用提供,开发者只要提供Settings Bundle这组文件即可.开发者为应用提供了Settings Bundle之后,该应用的参数设置界面由系统的Settings应用提供,用户设置的程序参数也由Settings负责保存,每次打开Settings进行设置时,Settings负责读取用户设置的参数…..应用程序的参数设置界面、数据存储、读取逻辑的都由系统的Settings应用负责.
为项目增加一个Settings Bundle,步骤如下:

  1. 、单击Xcode主菜单的”File”—>”New”—>”File…”菜单项;
  2. 、选中”iOS”—>”Resource”分类下的”Settings Bundle”,然后单击”Next”按钮,系统进入保存对话框,将该Settings Bundle保存在项目的根目录下,文件名为”Settings.bundle”.


第三章:iOS的数据存储与IO_第7张图片
在Xcode中打开Settings.bundle包含的Root.plist文件,可以看到如下:
第三章:iOS的数据存储与IO_第8张图片

在iPhone Settings Schema节点下包含两个子节点:

  • (1)、Preference Items:该节点的类型为Array.该节点用于定义该Settings Bundle的设置界面.该节点下包含了Item0、Item1、Item2、Item3这4个节点.
  • (2)、Strings Filename:该节点的类型为String,值为Root.该节点的作用是告诉系统到*.lproj文件中找Root.strings文件作为国际化资源文件—读者可以在en.lproj文件中找到Root.strings文件,如果程序需要进行Settings Bundle国际化,则可增加zh-Hans.lproj等文件夹,并在这些国际化资源文件内增加Root.strings文件.

注意:plist属性文件的本质就是NSDictionary或NSArray,只不过plist属性文件对应的NSDictionary的key只能是NSString类型,而value可以是Boolean、NSData、NSDate、NSNumber、NSString、NSArray、NSDictionary类型.

单击右键,选择”Show Raw Keys/Values”菜单项,该属性编辑器将会显示更真实的、未经处理的key和value,如下图:

Item0、Item1、Item2、Item3每项对应Settings应用中的一个设置条目,每个设置条目用于设置一个应用程序参数,每项通常可指定如下4个通用项目:

  • (1)、Title:该项配置应用程序参数的显示标题;
  • (2)、Type:该项配置应用程序参数的类型.Type支持如下几个属性值.

    • ①、PSTextFieldSpecifier:该类型指定应用程序参数是一个文本框,可由用户输入该参数的值;
    • ②、PSTitleValueSpecifier:该类型指定应用程序参数与显示标题相同;
    • ③、PSToggleSwitchSpecifier:该类型指定应用程序参数表现为UISwitch控件,用户可通过该控件设置该参数为YES或NO;
    • ④、PSSliderSpecifier:该类型指定应用程序参数表现为UISlider控件,用户可通过该控件设置一个浮点值;
    • ⑤、PSMultiValueSpecifier:该类型指定应用程序参数表现为可供用户选择的列表,用户可通过该列表选择其中一个值;
    • ⑥、PSGroupSpecifier:该类型定义一个分组;
    • ⑦、PSChildPaneSpecifier:该类型定义一个子设置视图.当用户单击这种类型的设置项时,系统将会打开一个新的设置界面–定义这种类型的Item时,必须重新指定一个plist文件来定义子设置视图的界面.
  • (3)、Key:该项用于指定保存应用程序参数的key—系统底层会采用NSDictionary来保存这些应用程序参数,每个应用程序参数存入NSDctionary中都需要指定一个key,该项设置的值将会作为应用程序参数的key.

  • (4)、DefaultValue:该项指定应用程序参数的默认值.

(1)、设置分组
如下图:
这里写图片描述

(2)、设置文本框参数
将Type设为”PSTextFieldSpecifier”代表文本框参数–这个程序参数允许用户自由的输入参数值.文本框参数同样可通过Title、Key、Default指定参数的显示标题、保存参数的key、默认值.除此之外,文本款参数还可指定如下选项:

  • ①、AutocapitalizationType:用于指定该文本框的自动大写类型.该选项支持的值与UITextView的Capitalization属性支持的属性值完全相同.
  • ②、Autocorrection Type:用于指定该文本框的自动更正类型.该选项支持的值与UITextView的Correction属性支持的属性值完全相同.
  • ③、IsSecure:该属性值设为”YES”,表明这是一个密码输入框.
  • ④、KeyboardType:指定该文本框关联的虚拟键盘的类型.
    第三章:iOS的数据存储与IO_第9张图片

(3)、设置UISwitch参数
将Type设为”PSSwitchSpecifier”代表只支持YES或NO的参数–这个程序参数允许用户通过UISwitch控件来设置参数值.UISwitch参数同样可通过Key、Title、Default指定参数的保存参数的key、显示标题、默认值.
这里写图片描述
(4)、设置UISlider参数
将Type设为”PSSliderSpecifier”代表只支持浮点值的参数–这个程序参数允许用户通过UISlider控件设置参数值.UISlider参数同样可通过Key、Default指定保存参数的key、默认值.除此之外,UISlider还支持如下设置:

  • ①、Minimum Value:指定滑块位于该UISlider最左边时所代表的最小值;
  • ②、Maximum Value:指定滑块位于该UISlider最右边时所代表的最大值;
  • ③、Minimum ValueImage:指定位于该UISlider最左边代表最小值的图片;
  • ④、Maximum ValueImage:指定位于该UISlider最右边代表最大值的图片;

注意:需要将图片放在Settings Bundle中,才能被Settings Bundle访问.不能直接拖近Settings Bundle中,需要显示包内容,还有将图片复制进去.
第三章:iOS的数据存储与IO_第10张图片

(5)、设置多值参数
将Type设置”PSMultiValueSpecifier”,用于配置一个多值列表参数、用户可通过列表选择参数值.多值参数同样可通过Title、Key、Default指定参数的显示标题、保存参数的key、默认值.除此之外,多值参数还支持如下设置:

  • ①、Titles:需要提供Array集合,集合元素定义多个列表项的标题;
  • ②、Values:需要提供Array集合,集合元素定义多个列表项的值;


(6)、设置子设置视图
将Item5的Type设为”PSGroupSpecifier”和Item6的Type设为”PSChildPaneSpecifier”,用于配置子设置视图,子设置视图可通过Title设置显示标题,也可通过File设置子设置视图的plist文件名.
第三章:iOS的数据存储与IO_第11张图片

注意:该子设置视图需要一个My.plist文件,与Root.plist格式完全相同,需要创建一个My.plist文件,然后显示包内容,复制到Settings Bundle中.

第三章:iOS的数据存储与IO_第12张图片

2、使用NSUserDefaults读取、保存应用程序参数

获取NSUserDefaults单例:

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

获取NSUserDefault对象之后,可通过如下方法来获取、设置参数:

  • (1)、xxxForKey:(NSString *)key:根据指定的key来获取对象的参数值.随着参数值类型的不同,xxx可以随之改变;
  • (2)、setXxx:value forKey:(NSString *)key:设置参数;
    参数设置完成后,可调用NSUserDefault对象的synchronize方法进行保存;

例如:

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"你好,女神" forKey:@"key"];
[defaults synchronize];
NSString* name = [defaults objectForKey:@"key"];

注意:此处可读取,设置上述Settings Bundle中的值

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSLog(@"%@",[defaults objectForKey:@"name"]);
NSLog(@"%d",[defaults boolForKey:@"musicOn"]);
NSLog(@"%f",[defaults floatForKey:@"gameSpeed"]);
NSLog(@"%@",[defaults objectForKey:@"race"]);

三、属性列表

  • (1)、只有当NSArray、NSDictionary集合保存如下类型的对象后,才可调用 - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;方法执行保存.
    • ①、NSArray和NSMutableArray;
    • ②、NSDictionary和NSMutableDictionary;
    • ③、NSData和NSMutableData;
    • ④、NSString和NSMutableString;
    • ⑤、NSValue和NSNumber;
  • (2)、当恢复这些数据时,只要调用NSArray、NSDictionary的xxxWithContentsOfFile:(NSString *)filePath;方法执行初始化

四、对象归档和原生I/O API

如果程序需要保存一个自定义的实例,则可让该类实现NSCoding协议,并实现该协议中定义的 - (id)initWithCoder:(NSCoder )aDecoder; - (void)encodeWithCoder:(NSCoder )aCoder;两个方法,接下来可使用NSKeyedArchive进行归档,当程序需要回复该对象时,可使用NSKeyedUnarchive进行恢复.

五、使用SQLite数据库

(1)、终端下得数据库

①、创建文件夹:mkdir sqlite;
②、创建表:create table(if not exists)表名(字段名1,字段名2…);
③、显示表:.table;
④、删除表:drop table 表名;
⑤、插入语句:insert into 表名(字段名 1,字段名 2…) values(值 1,值 2…)
⑥、显示表内内容:select *from 表名;
⑦、删除表内数据:delete from 表名 —删除所有的数据
delete from 表名 where 条件 —删除一条数据
⑧、修改:update 表名 set 字段名 1= 值 1,字段名 2=值 2… where 条件;
⑨、查询:select 字段名 from 表名;
select 字段名 from 表名 limit n;查询n条数据
查询排序:select 字段名 from 表名 order by 字段名(desc);降序;
查询多个:select count(*) from 表名;表名数据项数;
select sum(uid) from 表名;uid的和
select avg(uid) from 表名;uid的平均
⑩、退出:.quit;
主要:主键 create table WUGONG(wid integer primary key auto increment name,uid);

(2)、iOS的SQLite编程

在项目中使用iOS的SQLite编程API,需要先完成下面两步:
①、为项目正价libsqlite3.dylib
第三章:iOS的数据存储与IO_第13张图片
②、在需要使用SQLite API的Objective-C类中使用如下代码导入libsqlite3.dylib

#import <sqlite3.h>

一般情况下,我们可以使用第三方数据库FMDBDemo开使用数据库,添加头文件

#import "FMDatabase.h"

(3)、创建数据库和表

//首先需要获取数据库存储路径
NSString* path = [NSHomeDirectory()  stringByAppendingPathComponent:@"Documents/data.db"];
_db = [[FMDatabase alloc] initWithPath:path];
//然后创建数据库:
//打开数据库
BOOL res = [_db open];
if (res == NO) {
NSLog(@"打开失败");
return;
}
//创建表
res = [_db executeUpdate:@"create table if not exists USER(name,image)"];
if (res == NO) {
NSLog(@"创建表失败");
[_db close];
return;
}
//插入数据
//NSNumber,NSString,NSData
NSData* data = UIImagePNGRepresentation(_imageView.image);
res = [_db executeUpdate:@"insert into USER values(?,?)",_nameField.text,data];
if (res == NO) {
NSLog(@"插入数据失败");
}
//关闭数据库
[_db close];

(4)、删除数据

BOOL res = [_db open];
if (res == NO) {
NSLog(@"打开失败");
return;
}
res = [_db executeUpdate:@"delete from USER where name=?",_nameField.text];
if (res == NO) {
NSLog(@"删除失败");
[_db close];
return;
}
NSLog(@"删除成功");
[_db close];

(5)、查询数据

BOOL res = [_db open];
if (res == NO) {
NSLog(@"打开失败");
return;
}
//查询
FMResultSet *set = [_db executeQuery:@"select *from USER"];
while ([set next]) {

//int
//int a = [set intForColumn:]
//NSNumber
//NSNumber* num = [set objectForColumnName:]
NSString *name = [set stringForColumn:@"name"];
//NSData *data = [set dataForColumn:@"image"];
NSLog(@"name = %@",name);
}
[_db close];

(6)、修改数据

BOOL res = [_db open];
if (res == NO) {
NSLog(@"打开失败");
return;
}
NSData *data = UIImagePNGRepresentation(_imageView.image);
//修改name;
//res = [_db executeUpdate:@"update USER set name=? where image=?",_nameField.text,data];
//修改image
res = [_db executeUpdate:@"update USER set image=? where name=?",data,_nameField.text];
if (res == NO) {
NSLog(@"修改失败");
[_db close];
return;
}
NSLog(@"修改成功");
[_db close];

六、使用Core Data框架

(1)、Core Data简介

Core Data是一个纯粹的面向对象框架,可用于管理实体以及实体之间的关联关系的持久化—所谓的持久化,指的是Core Data可以将实体保存到持久化存储设备中,也可以在需要的时候将他们取出来;

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

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

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

  • ①、托管对象模型(NSManagedObjectModel):该对象负责管理整个应用的所有实体以及实体之间的关联关系.当开发者使用Xcode的图形界面设计了实体与实体的关联关系之后,需要使用该对象来加载、管理应用的托管对象模型;
  • ②、持久化存储协调器(NSPersistentStoreCoordinator):负责管理底层的存储文件,例如SQLite数据库等.
  • ③、托管对象上下文(NSManagedObjectContext):该对象是Core Data的核心对象,应用程序对实体所做的增、删、改、查操作都需要通过该对象来完成.
  • ④、实体描述(NSEntityDescription):对象代表关于某个实体的描述信息,从某种程度来说,该对象相当于实体的抽象.实体描述定义了该实体的名字、实体的实现类,并用一个集合定义了该实体包含的所有属性.
  • ⑤、抓取请求(NSFetchRequest):该对象封装了查询实体的请求,包括程序需要查询那些实体、查询条件、排序规则等.抓取请求定义了本次查询的实体名字、抓取请求的查询条件(通过NSPredicate来表示),并用一个NSArray集合定义了所有的排序规则;

使用Core Data持久化操作的步骤大致如下:

  1. 、创建NSManagedObjectModel对象来加载管理应用的托管对象模型;
  2. 、以NSManagedObjectModel对象为基础,根据实际需要创建NSPersistentStoreCoordinator对象,该对象确定Core Data底层数据的存储形式;
  3. 、以NSManagedObjectModel对象为基础,创建NSManagedObjectContext,该对象是Core Data进行持久化访问的核心对象;
  4. 、对于普通的增、删、改、查操作,需要分别新建实体、删除实体、修改实体,然后调用NSManagedObjectContext对象的save:方法将这些修改保存在底层存储设备.
  5. 、如果要执行查询,则需要先创建NSFetchRequest对象,在调用NSManagedObjectContext的executeFetchRequest:error:方法执行查询,该方法返回所有匹配条件的实体组成的NSArray.

(2)、初始化Core Data项目

步骤如下:
①、为该项添加CoreData.framework框架;
第三章:iOS的数据存储与IO_第14张图片
②、创建一个”Data Model”文件;
第三章:iOS的数据存储与IO_第15张图片

③、初始化Core Data应用必须得核心API对象:NSManagedObjectModel、NSPersistentStoreCoordinator、NSManagedObjectContext.
例如:这些核心API对象都属于全局可用的对象,因此程序一般会在应用程序委托类中执行初始化:
应用程序委托类的接口部分:

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property(strong,nonatomic,readonly)NSManagedObjectModel* managedObjectModel;
@property(strong,nonatomic,readonly)NSManagedObjectContext* managedObjectContext;
@property(strong,nonatomic,readonly)NSPersistentStoreCoordinator* persistentStoreCoordinator;
@end
应用接口委托类的实现部分
@synthesize managedObjectContext = _managedObjectContext;
@synthesize manageObjectModel = _manageObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (void)saveContext{
    NSError *error = nil;
    //获取应用的托管对象的上下文
    NSManagedObjectContext* managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        //如果托管对象上下文中包含了未保存的修改,则执行保存,如果保存失败则记录错误信息
        if ([managedObjectContext hasChanges]&&![managedObjectContext save:&error]) {
            NSLog(@"保存出现错误:%@,%@",error,[error userInfo]);
        }
    }
}
//托管对象
-(NSManagedObjectModel *)managedObjectModel
{
    //如果_managedObjectModel已经被初始化,则直接返回该对象
    if (_managedObjectModel!=nil) {
        return _managedObjectModel;
    }
    //获取实体模型文件对象的NSURL
    NSURL* modelURL=[[NSBundle mainBundle] URLForResource:@"User" withExtension:@"momd"];
    //加载应用的实体模型文件,并初始化NSManagedObjectModel对象
    _managedObjectModel=[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    // _managedObjectModel=[NSManagedObjectModel mergedModelFromBundles:nil];
    return _managedObjectModel;
}
//持久化存储协调器
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
    //如果_persistentStoreCoordinator已经被初始化过,则直接返回该对象
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    //获取SQLite数据库文件的存储目录
    NSURL* storeURL = [[self applicationDocumentDirectory]URLByAppendingPathComponent:@"Books.sqlite"];
    NSError* error;
    //以持久化对象模型为基础,创建NSPersistentStoreCoordinator对象
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:[self manageObjectModel]];
    //设置持久化存储协调器底层采用SQLite存储机制,如果设置失败记录错误信息
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"保存出现错误:%@,%@",error,[error userInfo]);
        //异常退出
        abort();
    }
    return _persistentStoreCoordinator;
}
//获取目录的Document目录
- (NSURL *)applicationDocumentDirectory{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]lastObject];
}
//初始化应用的托管上下文
- (NSManagedObjectContext *)managedObjectContext{
    //如果_managedObjectContext已经被初始化过,则直接返回该对象
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }
    //获取持久化存储协调器
    NSPersistentStoreCoordinator* coordinator = [self persistentStoreCoordinator];
    //如果持久化存储协调器不为nil
    if (coordinator != nil) {
        //创建NSManagedObjectContext对象
        _managedObjectContext = [[NSManagedObjectContext alloc]init];
        //为NSManagedObjectContext对象配置持久化存储协调器
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}
- (void)applicationWillTerminate:(UIApplication *)application {
    [self saveContext];
}

(3)、设计实体模型

第三章:iOS的数据存储与IO_第16张图片
对象模型可以添加如下3个属性:

  • ①、实体:这是实体模型最核心的对象,每个实体都必须是NSManagedObject类或其子类;
  • ②、抓取请求:NSFetchRequest对象,Xcode允许在图形界面上设计抓取请求对象.但实际上,我们通常会在代码创建NSFetchRequest对象;
  • ③、配置:一般无需自定添加配置对象.当开发者添加实体后,系统会自动添加默认的配置.

每个实体也可以添加如下3种属性:

  • ①、属性(Attribute):该属性相当于实体对象的实例变量,用于记录该实体的状态;
  • ②、关联关系(Relationships):该属性定义实体之间的1:1、1:N、N:N关联关系;
  • ③、抓取属性:(Fethed Properties):这是关联关系的可选方法,抓取属性允许在获取关联实体时执行某个过滤条件;

这里写图片描述添加实体、抓取请求、配置的按钮;
为实体添加属性的按钮;
切换显示方式的按钮;
这里写图片描述实体列表;
这里写图片描述抓取请求列表;
配置列表;

第三章:iOS的数据存储与IO_第17张图片此处列出指定实体的所有属性;
第三章:iOS的数据存储与IO_第18张图片此处列出指定实体的所有关联关系;

实例:添加一个简单的实体

  • ①、单击”Add Entity”按钮,系统将会在ENTITIES列表下添加一个实体,将该实体重命名为项目所需的名字;
    提示:长按”Add Entity”按钮,该按钮将会显示Add Entity、Add Fetch Request、Add Configuration列表,开发者可以选择其中一项来添加实体、抓取请求、配置.
  • ②、FKEntity实体中,通过点击右下角的”Add Attribute”按钮,系统将会为该FKEntity实体添加一个属性,就爱那个该属性命名为所需的名字.例如:名字:name 类型:String;

提示:长按”Add Attribute”按钮,该按钮将会显示Add Attribute、Add Relationship、Add Fetched Property列表,开发者可以选择其中一项来添加属性、关联关系、抓取属性.开发者也可以通过属性栏,关联关系栏、抓取属性栏下放的”+”、”-“按钮进行添加、删除.

  • ③、单击Xcode主菜单的”Editor”—>”Create NSManagedObject Subclass”菜单项,选择对应的实体,,然后再选择对应的路径,点击”Create”按钮将会根据选择的实体创建NSManagedObject的子类.

(4)、使用Core Data实现数据的增、删、改、查

(1)、添加实体:

步骤如下:

  • ①、调用NSEntityDescription的insertNewObjectForEntityForName:inManagedObjectContext:静态方法添加新实体.该对象的第一个参数为实体名,第二个从哪回溯为NSManagedObjectContext对象.
  • ②、为新实体设置属性;
  • ③、调用NSManagedObjectContext对象的save:方法执行保存.

例如如下代码:

self.appDelegate =[UIApplication sharedApplication].delegate;
CXUser* event = [NSEntityDescription insertNewObjectForEntityForName:@"CXUser" inManagedObjectContext:self.appDelegate.managedObjectContext];
// 为新实体设置属性
[event setName:@"xioaixao"];
// 定义一个NSError对象,用于接收错误信息
NSError* error;
//设置完实体属性之后,调用托管对象上下文的save:方法将实体写入数据库,如果保存成功
if ([self.appDelegate.managedObjectContext save:&error]) {
    NSLog(@"保存成功");
}else{
    NSLog(@"保存实体出错:%@,%@",error,[error userInfo]);
}

(2)、删除实体:

删除实体的步骤如下:

  • ①、获取要删除的实体;
  • ②、调用NSManagedObjectContext对象的deleteObjectL方法删除实体;
  • ③、调用NSManagedObjectContext对象的save:方法执行保存.

例如:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setIncludesPropertyValues:NO];
[request setEntity:entity];
NSError *error = nil;
NSArray *datas = [self.appDelegate.managedObjectContext executeFetchRequest:request error:&error];
if (!error && datas && [datas count])
{
    for (NSManagedObject *obj in datas){
        [self.appDelegate.managedObjectContext deleteObject:obj];
    }
    if (![self.appDelegate.managedObjectContext save:&error])
    {
        NSLog(@"error:%@",error);
    }else{
        NSLog(@"删除成功");
    }
}

(3)、修改实体:

修改实体的步骤如下:

  • ①、获取将要修改的实体(必须是出于NSManagedObjectContext管理下的实体);
  • ②、修改实体的属性;
  • ③、调用NSManagedObjectContext对象的save:方法执行保存;

例如:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"CXUser" inManagedObjectContext:self.appDelegate.managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setIncludesPropertyValues:NO];
[request setEntity:entity];
NSArray *datas = [self.appDelegate.managedObjectContext executeFetchRequest:request error:&error];
if (!error && datas && [datas count])
{
    for (CXUser *obj in datas){
        if ([obj.name isEqualToString:@"xiaoxiao"]) {
            [obj setName:@"bukuang"];
        }
    }
    if (![self.appDelegate.managedObjectContext save:&error])
    {
        NSLog(@"error:%@",error);
    }else{
        NSLog(@"修改成功");
    }
}

(4)、查询实体:

查询实体的步骤如下:

  • ①、创建NSFetchRequest对象;
  • ②、通过NSEntityDescription对象设置NSFetchRequest对象将要抓取的实体;
  • ③、如果过需要对抓取结果进行筛选,则需要通过NSPredicate对象设置筛选条件.如果需要对结果进行排序,还需要为NSFetchRequest添加多个NSSortDescriptor对象.

例如:

//设置想要抓取那种类型的实体
NSEntityDescription *entity = [NSEntityDescription entityForName:@"CXUser" inManagedObjectContext:self.appDelegate.managedObjectContext];
//创建抓取数据的请求对象
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setIncludesPropertyValues:NO];
//设置抓取实体
[request setEntity:entity];
//设置抓取条件
// 设置条件过滤(搜索name中包含字符串"xiaoxiao"的记录,注意:设置条件过滤时,数据库SQL语句中的%要用*来代替,所以%xiaoxiao%应该写成*Itcast-1*)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*xiaoxiao*"];
request.predicate = predicate;
NSError* error;
NSArray *datas = [self.appDelegate.managedObjectContext executeFetchRequest:request error:&error];
if (!error && datas && [datas count])
     {
     for (CXUser* user in datas) {
NSLog(@"user = %@“,user.name); } }

(5)、管理实体的关联关系

以后再续;

你可能感兴趣的:(ios,数据库,数据存储)