iOS开发中本地存储主要有三种形式
应用沙盒
要想在本地存储数据,那就要知道一下什么是应用沙盒 ,其实很好理解应用沙盒就是应用的文件夹,与其余文件系统隔离。每个iOS应用都有本身的应用沙盒,应用必须待在本身的沙盒里,其它应用不能访问该沙盒。
如何获取应用沙盒路径,能够经过打印NSHomeDirectory()来获取应用沙盒路径,下图为打印路径结果:html
Melody_Zhy 是用户文件夹(样子是个小房子)
3CEC8EEB-C230-44BE-93B7-DF3B9A120A94 iOS8以后每次运行Xcode都会生成不一样的沙盒路径,不一样之处就是最后这个文件夹名,多是苹果为了安全着想android
首先咱们先来看下,应用沙盒里面都有什么ios
这里提一下Finder的快捷键 shift + com + g 能够前往任意路径的文件夹,所以咱们能够打印沙盒路径以后将沙盒路径复制到Finder前往路径文件夹中,前往应用沙盒。这是一个比较耽误事的方法!幸亏有一款叫作simpholders的app,它能够很简单的访问应用的沙盒路径,记得去下载simpholders2哦,第一代iOS8以后就不能用了,app很简单易懂,用下就会了~
如今咱们来看看应用沙盒里面这些文件夹都是作什么用的git
应用沙盒目录的常见获取方式
正如上面咱们所说:github
NSString *home = NSHomeDirectory();
第一种( !笨!)sql
// 利用沙盒根目录拼接字符串 NSString *homePath = NSHomeDirectory(); NSString *docPath = [homePath stringByAppendingString:@"/Documents"];
第二种( !还👌!)数据库
// 利用沙盒根目录拼接”Documents”字符串 NSString *homePath = NSHomeDirectory(); NSString *docPath = [homePath stringByAppendingPathComponent:@"Documents"];
可是不建议使用这种方法,由于不定哪天苹果大大就把文件名称改了呢-_-!编程
第三种( !~推荐~ !)数组
// NSDocumentDirectory 要查找的文件 // NSUserDomainMask 表明从用户文件夹下找 // 在iOS中,只有一个目录跟传入的参数匹配,因此这个集合里面只有一个元素 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"xxx.plist"];
这里我来详细的说下NSSearchPathForDirectoriesInDomains这个方法的几个参数 :
<#NSSearchPathDirectory directory#> 这个参数表明要查找的文件,是个枚举! 枚举你懂的点击去看看就知道了~
<#NSSearchPathDomainMask domainMask#> 这个参数表明从用户文件夹下找,也是枚举!
最后一个参数若是是NO的话,打印的路径会是这种形式~/Documents,咱们通常都会用YES,这样能够获取完整路径字符串!
这个方法的返回值是一个数组,但在iOS中,只有一个目录跟传入的参数匹配,因此这个集合里面只有一个元素,因此咱们取第一个元素!缓存
这里我只用上面的第三种方法!注意第一个参数!
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"student.data"];
NSString *tmp= NSTemporaryDirectory();
经过NSUserDefaults类存取该目录下的设置信息!
!!!这个下面会有介绍!!!
XML属性列表(plist)归档
plist的根Type只能是字典(NSDictionary)或者是数组(NSArray)因此归档时咱们只能将数组或字典保存到plist文件中,可是NSString也能经过归档保存到plist文件中同时它也能够经过stringWithContentsOfFile解档,它保存到plist中时Type是空的,Value是有值的!
NSArray *arr = [[NSArray alloc] initWithObjects:@"1", @"2", nil]; // NSDocumentDirectory 要查找的文件 // NSUserDomainMask 表明从用户文件夹下找 // 在iOS中,只有一个目录跟传入的参数匹配,因此这个集合里面只有一个元素 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"xxx.plist"]; [arr writeToFile:filePath atomically:YES];
NSString *filePath = [path stringByAppendingPathComponent:@"xxx.plist"]; // 解档 NSArray *arr = [NSArray arrayWithContentsOfFile:filePath]; NSLog(@"%@", arr);
Preference(偏好设置)
OC中有一个NSUserDefaults的单例,它能够用来存储用户的偏好设置,例如:用户名,字体的大小,用户的一些设置等,下面我用两个UISwitch来演示如何保存用户设置开关的关闭状态
// 获取用户偏好设置对象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // 保存用户偏好设置 [defaults setBool:self.one.isOn forKey:@"one"]; [defaults setBool:self.two.isOn forKey:@"two"]; // 注意:UserDefaults设置数据时,不是当即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。因此调用了set方法以后数据有可能尚未写入磁盘应用程序就终止了。 // 出现以上问题,能够经过调用synchornize方法强制写入 // 如今这个版本不用写也会立刻写入 不过以前的版本不会 [defaults synchronize];
// 读取用户偏好设置 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; self.one.on = [defaults boolForKey:@"one"]; self.two.on = [defaults boolForKey:@"two"];
NSKeyedArchiver归档(NSCoding)
只有遵照了NSCoding协议的类才能够用NSKeyedArchiver归档和NSKeyedUnarchiver解档,若是对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,能够直接用NSKeyedArchiver归档和NSKeyedUnarchiver解档~
下面我举的🌰是归档解档一个Student模型,所以该模型应该遵照NSCoding协议
- (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.name forKey:@"name"]; [coder encodeInteger:self.age forKey:@"age"]; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { self.age = [coder decodeIntegerForKey:@"age"]; self.name = [coder decodeObjectForKey:@"name"]; } return self; }
Student *s1 = [[Student alloc] init];
s1.name = @"zzz"; s1.age = 18; NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; // 这个文件后缀能够是任意的,只要不与经常使用文件的后缀重复便可,我喜欢用data NSString *filePath = [path stringByAppendingPathComponent:@"student.data"]; // 归档 [NSKeyedArchiver archiveRootObject:s1 toFile:filePath];
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; NSString *filePath = [path stringByAppendingPathComponent:@"student.data"]; // 解档 Student *s = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; NSLog(@"%@----%ld", s.name, s.age);
相关连接:iOS开发中本地数据存储的总结
以上的全部存储方法,都是覆盖存储。若是想要增长一条数据就必须把整个文件读出来,而后修改数据后再把整个内容覆盖写入文件。因此它们都不适合存储大量的内容,大量存储须要用SQLite、CoreData等!
相关连接:ios KeyChain中保存数据
相关连接:使用ASIHTTPRequest和ASIDownloadCache实现本地缓存
一、设置全局的Cache
在AppDelegate.h中添加一个全局变量
@interface AppDelegate : UIResponder { ASIDownloadCache *myCache; } @property (strong, nonatomic) UIWindow *window; @property (nonatomic,retain) ASIDownloadCache *myCache;
//自定义缓存 ASIDownloadCache *cache = [[ASIDownloadCache alloc] init]; self.myCache = cache; [cache release]; //设置缓存路径 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentDirectory = [paths objectAtIndex:0]; [self.myCache setStoragePath:[documentDirectory stringByAppendingPathComponent:@"resource"]]; [self.myCache setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
在AppDelegate.m中的dealloc方法中添加以下语句
[myCache release];
二、设置缓存策略
在实现ASIHTTPRequest请求的地方设置request的存储方式,代码以下
NSString *str = @"http://....../getPictureNews.aspx"; NSURL *url = [NSURL URLWithString:str]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; //获取全局变量 AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; //设置缓存方式 [request setDownloadCache:appDelegate.myCache]; //设置缓存数据存储策略,这里采起的是若是无更新或没法联网就读取缓存数据 [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy]; request.delegate = self; [request startAsynchronous];
我在这里采用的是手动清理数据的方式,在适当的地方添加以下代码,我将清理缓存放在了应用的设置模块:
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; [appDelegate.myCache clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
这里清理的是ASICachePermanentlyCacheStoragePolicy这种存储策略的缓存数据,若是更换其余的参数的话,便可清理对应存储策略的缓存数据。
SQLite3
以前的全部存储方法,都是覆盖存储。若是想要增长一条数据就必须把整个文件读出来,而后修改数据后再把整个内容覆盖写入文件。因此它们都不适合存储大量的内容。
1.字段类型
表面上SQLite将数据分为如下几种类型:
integer : 整数
real : 实数(浮点数)
text : 文本字符串
blob : 二进制数据,好比文件,图片之类的
实际上SQLite是无类型的。即无论你在创表时指定的字段类型是什么,存储是依然能够存储任意类型的数据。并且在创表时也能够不指定字段类型。SQLite之因此什么类型就是为了良好的编程规范和方便开发人员交流,因此平时在使用时最好设置正确的字段类型!主键必须设置成integer
2. 准备工做
准备工做就是导入依赖库啦,在iOS中要使用SQLite3,须要添加库文件:libsqlite3.dylib并导入主头文件,这是一个C语言的库,因此直接使用SQLite3仍是比较麻烦的。
3.使用
建立数据库并打开
操做数据库以前必须先指定数据库文件和要操做的表,因此使用SQLite3,首先要打开数据库文件,而后指定或建立一张表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/**
* 打开数据库并建立一个表
*/
- (void)openDatabase {
//1.设置文件名
NSString *filename = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@
"person.db"
];
//2.打开数据库文件,若是没有会自动建立一个文件
NSInteger result = sqlite3_open(filename.UTF8String, &_sqlite3);
if
(result == SQLITE_OK) {
NSLog(@
"打开数据库成功!"
);
//3.建立一个数据库表
char *errmsg = NULL;
sqlite3_exec(_sqlite3,
"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"
, NULL, NULL, &errmsg);
if
(errmsg) {
NSLog(@
"错误:%s"
, errmsg);
}
else
{
NSLog(@
"创表成功!"
);
}
}
else
{
NSLog(@
"打开数据库失败!"
);
}
}
|
执行指令
使用 sqlite3_exec() 方法能够执行任何SQL语句,好比创表、更新、插入和删除操做。可是通常不用它执行查询语句,由于它不会返回查询到的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 往表中插入1000条数据
*/
- (void)insertData {
NSString *nameStr;
NSInteger age;
for
(NSInteger i = 0; i < 1000; i++) {
nameStr = [NSString stringWithFormat:@
"Bourne-%d"
, arc4random_uniform(10000)];
age = arc4random_uniform(80) + 20;
NSString *sql = [NSString stringWithFormat:@
"INSERT INTO t_person (name, age) VALUES('%@', '%ld')"
, nameStr, age];
char *errmsg = NULL;
sqlite3_exec(_sqlite3, sql.UTF8String, NULL, NULL, &errmsg);
if
(errmsg) {
NSLog(@
"错误:%s"
, errmsg);
}
}
NSLog(@
"插入完毕!"
);
}
|
查询指令
前面说过通常不使用 sqlite3_exec() 方法查询数据。由于查询数据必需要得到查询结果,因此查询相对比较麻烦。示例代码以下:
sqlite3_prepare_v2() : 检查sql的合法性
sqlite3_step() : 逐行获取查询结果,不断重复,直到最后一条记录
sqlite3_coloum_xxx() : 获取对应类型的内容,iCol对应的就是SQL语句中字段的顺序,从0开始。根据实际查询字段的属性,使用sqlite3_column_xxx取得对应的内容便可。
sqlite3_finalize() : 释放stmt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 从表中读取数据到数组中
*/
- (void)readData {
NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1000];
char *sql =
"select name, age from t_person;"
;
sqlite3_stmt *stmt;
NSInteger result = sqlite3_prepare_v2(_sqlite3, sql, -1, &stmt, NULL);
if
(result == SQLITE_OK) {
while
(sqlite3_step(stmt) == SQLITE_ROW) {
char *name = (char *)sqlite3_column_text(stmt, 0);
NSInteger age = sqlite3_column_int(stmt, 1);
//建立对象
Person *person = [Person personWithName:[NSString stringWithUTF8String:name] Age:age];
[mArray addObject:person];
}
self.dataList = mArray;
}
sqlite3_finalize(stmt);
}
|
4.总结
总得来讲,SQLite3的使用仍是比较麻烦的,由于都是些c语言的函数,理解起来有些困难。不过在通常开发过程当中,使用的都是第三方开源库 FMDB,封装了这些基本的c语言方法,使得咱们在使用时更加容易理解,提升开发效率。
FMDB
1.简介
FMDB是iOS平台的SQLite数据库框架,它是以OC的方式封装了SQLite的C语言API,它相对于cocoa自带的C语言框架有以下的优势:
使用起来更加面向对象,省去了不少麻烦、冗余的C语言代码
对比苹果自带的Core Data框架,更加轻量级和灵活
提供了多线程安全的数据库操做方法,有效地防止数据混乱
2.核心类
FMDB有三个主要的类:
FMDatabase
一个FMDatabase对象就表明一个单独的SQLite数据库,用来执行SQL语句
FMResultSet
使用FMDatabase执行查询后的结果集
FMDatabaseQueue
用于在多线程中执行多个查询或更新,它是线程安全的
3.打开数据库
和c语言框架同样,FMDB经过指定SQLite数据库文件路径来建立FMDatabase对象,但FMDB更加容易理解,使用起来更容易,使用以前同样须要导入sqlite3.dylib。打开数据库方法以下:
1
2
3
4
5
|
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@
"person.db"
];
FMDatabase *database = [FMDatabase databaseWithPath:path];
if
(![database open]) {
NSLog(@
"数据库打开失败!"
);
}
|
值得注意的是,Path的值能够传入如下三种状况:
具体文件路径,若是不存在会自动建立
空字符串@"",会在临时目录建立一个空的数据库,当FMDatabase链接关闭时,数据库文件也被删除
nil,会建立一个内存中临时数据库,当FMDatabase链接关闭时,数据库会被销毁
4.更新
在FMDB中,除查询之外的全部操做,都称为“更新”, 如:create、drop、insert、update、delete等操做,使用executeUpdate:方法执行更新:
1
2
3
4
5
6
7
8
|
//经常使用方法有如下3种:
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
//示例
[database executeUpdate:@
"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"
];
//或者
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES(?, ?)"
, @
"Bourne"
, [NSNumber numberWithInt:42]];
|
5.查询
查询方法也有3种,使用起来至关简单:
1
2
3
|
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
|
查询示例:
1
2
3
4
5
6
7
|
//1.执行查询
FMResultSet *result = [database executeQuery:@
"SELECT * FROM t_person"
];
//2.遍历结果集
while
([result next]) {
NSString *name = [result stringForColumn:@
"name"
];
int age = [result intForColumn:@
"age"
];
}
|
6.线程安全
在多个线程中同时使用一个FMDatabase实例是不明智的。不要让多个线程分享同一个FMDatabase实例,它没法在多个线程中同时使用。 若是在多个线程中同时使用一个FMDatabase实例,会形成数据混乱等问题。因此,请使用 FMDatabaseQueue,它是线程安全的。如下是使用方法:
建立队列。
1
|
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
|
使用队列
1
2
3
4
5
6
7
8
|
[queue inDatabase:^(FMDatabase *database) {
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_1"
, [NSNumber numberWithInt:1]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_2"
, [NSNumber numberWithInt:2]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_3"
, [NSNumber numberWithInt:3]];
FMResultSet *result = [database executeQuery:@
"select * from t_person"
];
while
([result next]) {
}
}];
|
并且能够轻松地把简单任务包装到事务里:
1
2
3
4
5
6
7
8
9
10
|
[queue inTransaction:^(FMDatabase *database, BOOL *rollback) {
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_1"
, [NSNumber numberWithInt:1]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_2"
, [NSNumber numberWithInt:2]];
[database executeUpdate:@
"INSERT INTO t_person(name, age) VALUES (?, ?)"
, @
"Bourne_3"
, [NSNumber numberWithInt:3]];
FMResultSet *result = [database executeQuery:@
"select * from t_person"
];
while
([result next]) {
}
//回滚
*rollback = YES;
}];
|
FMDatabaseQueue 后台会创建系列化的G-C-D队列,并执行你传给G-C-D队列的块。这意味着 你从多线程同时调用调用方法,GDC也会按它接收的块的顺序来执行。
建立数据库
CoreData
-> DataModel
Add Entity
Attributes
下方的‘+’号建立模型文件
CoreData
-> NSManaged Object subclass
经过代码,关联数据库和实体
- (void)viewDidLoad { [super viewDidLoad]; /* * 关联的时候,若是本地没有数据库文件,Coreadata本身会建立 */ // 1. 上下文 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; // 2. 上下文关连数据库 // 2.1 model模型文件 NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; // 2.2 持久化存储调度器 // 持久化,把数据保存到一个文件,而不是内存 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; // 2.3 设置CoreData数据库的名字和路径 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqlitePath = [doc stringByAppendingPathComponent:@"company.sqlite"]; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:nil]; context.persistentStoreCoordinator = store; _context = context; }
添加元素 - Create
-(IBAction)addEmployee{ // 建立一个员工对象 //Employee *emp = [[Employee alloc] init]; 不能用此方法建立 Employee *emp = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_context]; emp.name = @"wangwu"; emp.height = @1.80; emp.birthday = [NSDate date]; // 直接保存数据库 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
读取数据 - Read
-(IBAction)readEmployee{ // 1.FetchRequest 获取请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2.设置过滤条件 // 查找zhangsan NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"zhangsan"]; request.predicate = pre; // 3.设置排序 // 身高的升序排序 NSSortDescriptor *heigtSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:NO]; request.sortDescriptors = @[heigtSort]; // 4.执行请求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } //NSLog(@"%@",emps); //遍历员工 for (Employee *emp in emps) { NSLog(@"名字 %@ 身高 %@ 生日 %@",emp.name,emp.height,emp.birthday); } }
修改数据 - Update
-(IBAction)updateEmployee{ // 改变zhangsan的身高为2m // 1.查找到zhangsan // 1.1FectchRequest 抓取请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 1.2设置过滤条件 // 查找zhangsan NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"zhangsan"]; request.predicate = pre; // 1.3执行请求 NSArray *emps = [_context executeFetchRequest:request error:nil]; // 2.更新身高 for (Employee *e in emps) { e.height = @2.0; } // 3.保存 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
删除数据 - Delete
-(IBAction)deleteEmployee{ // 删除 lisi // 1.查找lisi // 1.1FectchRequest 抓取请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 1.2设置过滤条件 // 查找zhangsan NSPredicate *pre = [NSPredicate predicateWithFormat:@"name = %@", @"lisi"]; request.predicate = pre; // 1.3执行请求 NSArray *emps = [_context executeFetchRequest:request error:nil]; // 2.删除 for (Employee *e in emps) { [_context deleteObject:e]; } // 3.保存 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
建立数据库
CoreData
-> DataModel
Add Entity
, 注意:这里根据关联添加多个实体Attributes
下方的‘+’号建立模型文件
CoreData
-> NSManaged Object subclass
经过代码,关联数据库和实体
- (void)viewDidLoad { [super viewDidLoad]; /* * 关联的时候,若是本地没有数据库文件,Coreadata本身会建立 */ // 1. 上下文 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; // 2. 上下文关连数据库 // 2.1 model模型文件 NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; // 2.2 持久化存储调度器 // 持久化,把数据保存到一个文件,而不是内存 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; // 2.3 设置CoreData数据库的名字和路径 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqlitePath = [doc stringByAppendingPathComponent:@"company.sqlite"]; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:nil]; context.persistentStoreCoordinator = store; _context = context; }
添加元素 - Create
-(IBAction)addEmployee{ // 1. 建立两个部门 ios android //1.1 iOS部门 Department *iosDepart = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:_context]; iosDepart.name = @"ios"; iosDepart.departNo = @"0001"; iosDepart.createDate = [NSDate date]; //1.2 Android部门 Department *andrDepart = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:_context]; andrDepart.name = @"android"; andrDepart.departNo = @"0002"; andrDepart.createDate = [NSDate date]; //2. 建立两个员工对象 zhangsan属于ios部门 lisi属于android部门 //2.1 zhangsan Employee *zhangsan = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_context]; zhangsan.name = @"zhangsan"; zhangsan.height = @(1.90); zhangsan.birthday = [NSDate date]; zhangsan.depart = iosDepart; //2.2 lisi Employee *lisi = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_context]; lisi.name = @"lisi"; lisi.height = @2.0; lisi.birthday = [NSDate date]; lisi.depart = andrDepart; //3. 保存数据库 NSError *error = nil; [_context save:&error]; if (error) { NSLog(@"%@",error); } }
读取信息 - Read
-(IBAction)readEmployee{ // 读取ios部门的员工 // 1.FectchRequest 抓取请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2.设置过滤条件 NSPredicate *pre = [NSPredicate predicateWithFormat:@"depart.name = %@",@"android"]; request.predicate = pre; // 4.执行请求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } //遍历员工 for (Employee *emp in emps) { NSLog(@"名字 %@ 部门 %@",emp.name,emp.depart.name); } }
其余功能与前几种相似,这里不在赘述
准备工做和上面相似,主要是查询方式不一样
模糊查询
-(IBAction)readEmployee{ // 1.FectchRequest 抓取请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2.设置排序 // 按照身高的升序排序 NSSortDescriptor *heigtSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:NO]; request.sortDescriptors = @[heigtSort]; // 3.模糊查询 // 3.1 名字以"wang"开头 // NSPredicate *pre = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@",@"wangwu1"]; // request.predicate = pre; // 名字以"1"结尾 // NSPredicate *pre = [NSPredicate predicateWithFormat:@"name ENDSWITH %@",@"1"]; // request.predicate = pre; // 名字包含"wu1" // NSPredicate *pre = [NSPredicate predicateWithFormat:@"name CONTAINS %@",@"wu1"]; // request.predicate = pre; // like 匹配 NSPredicate *pre = [NSPredicate predicateWithFormat:@"name like %@",@"*wu12"]; request.predicate = pre; // 4.执行请求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } //遍历员工 for (Employee *emp in emps) { NSLog(@"名字 %@ 身高 %@ 生日 %@",emp.name,emp.height,emp.birthday); } }
分页查询
-(void)pageSeacher{ // 1. FectchRequest 抓取请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"]; // 2. 设置排序 // 身高的升序排序 NSSortDescriptor *heigtSort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:NO]; request.sortDescriptors = @[heigtSort]; // 3. 分页查询 // 总有共有15数据 // 每次获取6条数据 // 第一页 0,6 // 第二页 6,6 // 第三页 12,6 3条数据 // 3.1 分页的起始索引 request.fetchOffset = 12; // 3.2 分页的条数 request.fetchLimit = 6; // 4. 执行请求 NSError *error = nil; NSArray *emps = [_context executeFetchRequest:request error:&error]; if (error) { NSLog(@"error"); } // 5. 遍历员工 for (Employee *emp in emps) { NSLog(@"名字 %@ 身高 %@ 生日 %@",emp.name,emp.height,emp.birthday); } }
注意:
建立多个数据库,即建立多个
DataModel
一个数据库对应一个上下文
须要根据bundle名建立上下文
添加或读取信息,须要根据不一样的上下文,访问不一样的实体
关联数据库和实体
- (void)viewDidLoad { [super viewDidLoad]; // 一个数据库对应一个上下文 _companyContext = [self setupContextWithModelName:@"Company"]; _weiboContext = [self setupContextWithModelName:@"Weibo"]; } /** * 根据模型文件,返回一个上下文 */ -(NSManagedObjectContext *)setupContextWithModelName:(NSString *)modelName{ // 1. 上下文 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; // 2. 上下文关连数据库 // 2.1 model模型文件 // 注意:若是使用下面的方法,若是 bundles为nil 会把bundles里面的全部模型文件的表放在一个数据库 //NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil]; // 改成如下的方法获取: NSURL *companyURL = [[NSBundle mainBundle] URLForResource:modelName withExtension:@"momd"]; NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:companyURL]; // 2.2 持久化存储调度器 // 持久化,把数据保存到一个文件,而不是内存 NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; // 2.3 告诉Coredata数据库的名字和路径 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *sqliteName = [NSString stringWithFormat:@"%@.sqlite",modelName]; NSString *sqlitePath = [doc stringByAppendingPathComponent:sqliteName]; [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlitePath] options:nil error:nil]; context.persistentStoreCoordinator = store; // 3. 返回上下文 return context; }
添加元素
-(IBAction)addEmployee{ // 1. 添加员工 Employee *emp = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:_companyContext]; emp.name = @"zhagsan"; emp.height = @2.3; emp.birthday = [NSDate date]; // 直接保存数据库 [_companyContext save:nil]; // 2. 发微博 Status *status =[NSEntityDescription insertNewObjectForEntityForName:@"Status" inManagedObjectContext:_weiboContext]; status.text = @"发了一条微博!"; status.createDate = [NSDate date]; [_weiboContext save:nil]; }