缓存分为:内存缓存 和 数据持久化(磁盘缓存)
内存缓存:
内存缓存是指当前程序运行空间,内存缓存速度快容量小,它是供cpu直接读取,
比如我们打开一个程序,他是运行在内存中的,关闭程序后内存又会释放。
常用框架:NSCache, YYMemoryCache.
我们常说的分区(从高地址到低地址):栈区,堆区, 全局区, 常量区, 代码区。 就是内存的范畴。
所以内存缓存指的就是将数据存储到这些区域。 一般是将数据缓存到堆区。
频繁的从磁盘中读取数据是比较耗性能的。 所以一般是先从磁盘中取到数据,存到内存缓存中,以达到性能优化。
磁盘缓存
就是 数据持久化。
就是将数据保存到硬盘中(沙盒中),使得在应用程序或机器重启后可以继续访问之前保存的数据。
沙盒的结构
沙盒的路径
NSHomeDirectory();
1、Documents
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
2、Library
2.1 Caches
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
2.2 Preference
这个文件夹里存的是 通过NSUserDefault 方式存储的plist文件
//获取Preferences目录. 通常情况下,Preferences有系统维护,所以我们很少去操作它。
NSString *preferPath = [LibraryPath stringByAppendingPathComponent:@"Preferences"];
3、tmp
NSString *path = NSTemporaryDirectory();
缓存存放路径的规定:
用户生成的文件放在documents,自己的文件放在library/cache里面。
如果你做个记事本的app,那么用户写了东西,总要把东西存起来。那么这个文件则是用户自行生成,就放在documents文件夹里面。
如果你有一个app,需要和服务器配合,经常从服务器下载东西,展示给用户看。那么这些下载下来的东西就放在library/cache。
使用**Xcode**获取沙盒文件**(**模拟器和真机**)** 查看沙盒内容
[https://blog.csdn.net/wangxiaopeng1103/article/details/52947521](https://blog.csdn.net/wangxiaopeng1103/article/details/52947521)
数据持久化存储的几种方式:
[https://blog.csdn.net/jiankeufo/article/details/79347330](https://blog.csdn.net/jiankeufo/article/details/79347330)
**1.plist**文件
这个方法可以指定存储在沙盒的路径。
writeToFile方法。
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];
NSArray *array = @[@"123", @"456", @"789"];
[array writeToFile:fileName atomically:YES];
NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"%@", result);
**2.**偏好设置**preference**
在沙盒的preference目录下的一个以此应用包名来命名的plist文件。
NSUserDefaults存储不可变类型数据
//1.获得NSUserDefaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中写入内容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1立即同步
[userDefaults synchronize];
//3.读取文件
NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);
**3.**归档**NSKeyedArchiver** 解档**NSKeyedUnarchiver**
遵循NSCoding
存储的是 .data文件
//1.遵循NSCoding协议
@interface Person : NSObject <NSCoding>
//2.设置属性
@property (strong, nonatomic) UIImage *avatar;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
@end
//实现协议的两个方法
//解档
- (id)initWithCoder:(NSCoder *)aDecoder {
if ([super init]) {
self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.avatar forKey:@"avatar"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
使用:
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
Person *person = [[Person alloc] init];
person.avatar = self.avatarView.image;
person.name = self.nameField.text;
person.age = [self.ageField.text integerValue];
//写入person.data文件
[NSKeyedArchiver archiveRootObject:person toFile:file];
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
//根据person.data文件读取数据
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
if (person) {
self.avatarView.image = person.avatar;
self.nameField.text = person.name;
self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
}
FMDB
[https://www.cnblogs.com/Yun-Longcom/p/6008724.html](https://www.cnblogs.com/Yun-Longcom/p/6008724.html)
SQL语法
[https://blog.csdn.net/m0_37177053/article/details/78350202](https://blog.csdn.net/m0_37177053/article/details/78350202)
FMDatabase : 一个单一的SQLite数据库,用于执行SQL语句。
FMResultSet :执行查询一个FMDatabase结果集。
FMDatabaseQueue :在多个线程来执行查询和更新时会使用这个类
首先创建数据库:
NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path=[path stringByAppendingPathComponent:@"test.sqlite"];
FMDatabase *dataBase= [FMDatabase databaseWithPath:path]; //数据库有数据库的名称 test.sqlite
创建表:
NSString * create1=@"create table if not exists t_user(id integer autoincrement primary key,name varchar)";
**BOOL c1= [dataBase executeUpdate:create1]; //**表有表的名称 **t_user**
插入数据
**NSString * insertSql = @"insert into t_user(id,name) values(?,?)";**
bool inflag1 = [dataBase executeUpdate:insertSql,@(2),@"admin"];
if(inflag1){
NSLog(@“增加成功");
}
删除语句
**NSString * delete=@"delete from t_user";**
BOOL dflag= [dataBase executeUpdate:delete];
if(dflag){
NSLog(@"删除成功");
}
修改语句
**NSString *update=@" update t_user set name=? ";**
BOOL flag= [dataBase executeUpdate:update,@"zhangsan"];
if(flag){
NSLog(@"修改成功");
}
查询语句
**NSString * sql=@" select * from t_user ";**
**FMResultSet *result=[dataBase executeQuery:sql];**
while(result.next){
int ids=[result intForColumn:@"id"];
NSString * name=[result stringForColumn:@"name"];
int ids=[result intForColumnIndex:0];
NSString * name=[result stringForColumnIndex:1];
NSLog(@"%@,%d",name, ids);
}
注意:
创建表,增,删,改 都使用executeUpdate方法
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
只有查询使用executeQuery方法
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
多线程的操作
如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。
应用中不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。
为了多线程操作数据库安全,FMDB使用了FMDatabaseQueue。
使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与FMDatabase的管理
NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path=[path stringByAppendingPathComponent:@"test.sqlite"];
//创建一个test.sqlite数据库
FMDatabaseQueue *queue=[FMDatabaseQueue databaseQueueWithPath:path];
[queue inDatabase:^(FMDatabase *db) {
//创建一个t_book表。
NSString * create=@"create table if not exists t_book(id integer,name varchar)";
BOOL c1= [db executeUpdate:create];
if(c1){
NSLog(@"成功");
}
}];
[queue inDatabase:^(FMDatabase *db) {
NSString * insertSql=@"insert into t_book(id,name) values(?,?)";
//插入语句1
bool inflag=[db executeUpdate:insertSql,@(2),@"admin"];
if(inflag){
NSLog(@"插入成功");
}
}];
[queue inDatabase:^(FMDatabase *db) {
//查询语句1
FMResultSet *data = [db executeQuery:@" select * from t_book "];
while (data.next) {
int ids=[data intForColumn:@"id"];
NSString *name=[data stringForColumn:@"name"];
NSLog(@"%@",name);
NSLog(@"%i",ids);
}
}];