目录
一、沙盒

* 每个iOS应用程序都有自己独立的存储空间,此区域称为沙盒。应用只在自己的沙盒中操作,其它应用程序无法访问该沙盒。
* 数据持久化就是将数据存储到沙盒中。
* 数据持久化操作的沙盒文件目录:
文件夹 | 备份 | 使用 |
---|---|---|
Douments | YES | 使用此目录保存用户数据,该目录的内容可以通过文件共享提供给用户,因此这里存储希望向用户公开的文件。可以是用户创建、导入、删除或编辑的任何文件,例如:绘图类APP用户可能创建的任何图形文件;文本编辑类APP产生的文本文件;视频、音频类APP用户下载后的视频、音频文件。 因为Documents/中的文件默认情况下是会备份的,任何可以重新创建或下载的文件都必须从备份中排出,特别是大型媒体文件,例如:视频APP下载的视频、音乐APP下载的歌曲。可以用调用下面方法来排除:-[NSURL setResourceValue:forKey:error:] ,其中key用 NSURLIsExcludedFromBackupKey 。 |
Library | YES(除Caches外) | 这是所有非用户数据的顶级目录。希望被备份但不希望用户看到的数据,例如APP的默认设置或其它状态信息。系统在Library目录下创建了Catches和Preferences两个子目录,通常直接使用这两个子目录,也可以创建自定义的子目录。 |
Library/Preferences | YES | 包含了存储应用程序偏好设置的plist文件,通过NSUserDefaults来读写。 |
Library/Caches | NO | 缓存数据,可以保存任何比临时数据(tmp中存储的数据)持久时间更长的数据,一般来说,APP没有缓存数据也要能正常运行,但它可以使用缓存数据来提高性能。因为系统可能会删除缓存数据来释放磁盘空间。 |
tmp | NO | 临时数据,可以保存任何在APP运行期间需要的临时数据,当不再需要时应及时删除,这样不会继续占用用户设备上的空间,应用程序不运行时系统会定期清除这些文件。 |
Documents路径:
NSString *documentDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
Library路径:
NSString *libraryDirectory = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject;
Preferences使用
NSUserDefaults *userDufaults = [NSUserDefaults standardUserDefaults];
Caches路径
NSString *catchesDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
tmp路径
NSString *tmpDirectory = NSTemporaryDirectory();
二、数据持久化方式
* 常用几种数据持久化方式对比
持久化方式 | 使用 |
---|---|
属性列表plist | 1、用来存储少量数据 2、无法将自定义对象序列化到属性列表中,只能存储下列数据类型: NSNumber NSDate NSData/NSMutableData NSArray/NSMutableArray NSDictionary/NSMutableDictionary NSString/NSMutableString |
NSUserDefaults | 1、用来存储少量数据,一般用来保存应用配置信息 2、使用简单,但数据保存位置固定(都保存在Preferences文件夹下以应用包命名的plist文件) 3、无法将自定义对象序列化到属性列表中 |
对象归档 | 1、用来存储少量数据。(解档时会一次性全部取出文件中内容,存储大型数据会比较消耗资源) 2、弥补了前两种方式无法存储自定义类的不足,能存储遵循NSCoding协议的自定义对象 |
FMDB | 1、数据库,存储复杂的数据 |
* 属性列表plist
//待存数据
NSArray *array = @[@"A",@"B",@"C"];
//Documents文件夹路径
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
//待存文件路径
NSString *fileName = [documentPath stringByAppendingPathComponent:@"TestData.plist"];
//如果是新建文件路径,可以先判断创建的文件路径是否已经存在了,避免数据被覆盖。
NSFileManager *fileManage = [NSFileManager defaultManager];
if ([fileManage fileExistsAtPath:fileName]) {
NSLog(@"已经存在TestData.plist文件");
}else{
NSLog(@"存在TestData.plist文件");
}
//写入。(atomically:YES 先创建一个辅助文件,如果写入成功再把辅助文件写入目标地址,更安全,因为如果在写入过程中程序崩溃了,原文件(如果有)不会被破坏,只是效率会低一些,一般都用YES;反之不安全但效率高。)
BOOL writeSuccess = [array writeToFile:fileName atomically:YES];
if (writeSuccess) {
NSLog(@"写入成功");
}
//读取
NSArray *arr = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"plist:%@",arr);
* 偏好设置Preference
//用NSUserDefaults操作
NSUserDefaults *userDufaults = [NSUserDefaults standardUserDefaults];
//写入
[userDufaults setBool:YES forKey:@"isCloss"];
//NSUserDefaults是定时把缓存中的数据写入磁盘的,而不是即时写入,为了防止在写完NSUserDefaults后程序退出导致的数据丢失,可以在写入数据后使用synchronize强制立即将数据写入磁盘
[userDufaults synchronize];
//读取
BOOL isCloss = [userDufaults boolForKey:@"isCloss"];
* 对象归档(以下只例举了自定义类的归档方法)
/*
* PeopleModel.h
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PeopleModel : NSObject<NSCoding>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger ID;
@end
NS_ASSUME_NONNULL_END
/*
* PeopleModel.m
*/
#import "PeopleModel.h"
@implementation XMPeopleModel
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeInteger:_age forKey:@"age"];
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInteger:_ID forKey:@"ID"];
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
self.ID = [aDecoder decodeIntegerForKey:@"ID"];
}
return self;
}
/*
归档实现代码
*/
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [documentPath stringByAppendingPathComponent:@"people.plist"];
XMPeopleModel *peopleModel = [[XMPeopleModel alloc] init];
peopleModel.name = @"Tony";
peopleModel.age = 28;
//归档
if ([NSKeyedArchiver archiveRootObject:peopleModel toFile:filePath]) {
NSLog(@"Tony 归档成功");
}
//反归档
XMPeopleModel *people = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
* FMDB(基本方法示例)
//创建database路径
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *dbPath = [documentPath stringByAppendingPathComponent:@"fmdb.sqlite"];
//创建对应路径下的数据库
db_ = [FMDatabase databaseWithPath:dbPath];
//打开数据库
if ([db_ open]) {
NSLog(@"打开数据库成功!");
}else{
NSLog(@"打开数据库失败");
}
//数据库中创建表(可创建多张)
NSString *createSql = @"CREATE TABLE IF NOT EXISTS t_people (name text NOT NULL,age integer NOT NULL);";//b如果不存在t_people表,就创建该表。
if ([db_ executeUpdate:createSql]) {
NSLog(@"t_people表创建成功");
}else{
NSLog(@"t_people表创建失败");
}
//待存数据
XMPeopleModel *peopleA = [[XMPeopleModel alloc] init];
peopleA.name = @"Amy";
peopleA.age = 19;
XMPeopleModel *peopleB = [[XMPeopleModel alloc] init];
peopleB.name = @"Tony";
peopleB.age = 29;
//插入数据
BOOL resultA = [db_ executeUpdate:@"INSERT INTO t_people (name,age) VALUES (?,?)" withArgumentsInArray:@[peopleA.name,@(peopleA.age)]];
//[db_ executeUpdateWithFormat:@"INSERT INTO t_people (name,age) VALUES (%@,%ld)",peopleA.name,(long)peopleA.age];
if (resultA) {
NSLog(@"Amy插入成功");
}else {
NSLog(@"Amy插入失败");
}
BOOL resultB = [db_ executeUpdateWithFormat:@"INSERT INTO t_people (name,age) VALUES (%@,%ld)",peopleB.name,(long)peopleB.age];
if (resultB) {
NSLog(@"Tony插入成功");
}else {
NSLog(@"Tony插入失败");
}
//更新数据
BOOL updateResult = [db_ executeUpdate:@"UPDATE t_people SET name = ? WHERE name = ?",@"Tony2",@"Tony"];
if (updateResult) {
NSLog(@"Tony名字改成Tony2");
}else{
NSLog(@"Tony改名失败");
}
//删除数据
BOOL deleteResult = [db_ executeUpdate:@"DELETE FROM t_people WHERE name = ?",@"Tony"];
if (deleteResult) {
NSLog(@"删除Tony成功");
}else{
NSLog(@"删除Tony失败");
}
//查询数据
FMResultSet *resultSet = [db_ executeQuery:@"SELECT * FROM t_people"];//查询整个表
while ([resultSet next]) {
NSString *name = [resultSet stringForColumn:@"name"];
NSInteger age = [resultSet intForColumn:@"age"];
NSLog(@"%@今年%ld岁了",name,(long)age);
}
FMResultSet *resultSetTony = [db_ executeQuery:@"SELECT * FROM t_people WHERE name = ?",@"Tony"];//根据条件查询
while ([resultSetTony next]) {
NSString *TonyName = [resultSetTony stringForColumn:@"name"];
NSInteger TonyAge = [resultSetTony intForColumn:@"age"];
NSLog(@"%@老师%ld大寿",TonyName,TonyAge);
}
//销毁表
BOOL dropResult = [db_ executeUpdate:@"DROP TABLE IF EXISTS t_people"];
if (dropResult) {
NSLog(@"删除t_people表");
}else{
NSLog(@"未能删除t_people表");
}
* FMDB(单例用法示例)
/*
单例 XMDataBase.h
*/
#import <Foundation/Foundation.h>
#import "PeopleModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface XMDataBase : NSObject
+ (instancetype)shareInstance;
//增
- (BOOL)addPerson:(PeopleModel *)person;
//删
- (BOOL)deletePersonWithID:(NSInteger)ID;
//改
- (BOOL)updatePerson:(PeopleModel *)person;
//查
- (NSArray *)getAllPeople;
- (PeopleModel *)getPersonWithID:(NSInteger)ID;
//销毁
- (BOOL)dropTable:(NSString *)tableName;
@end
NS_ASSUME_NONNULL_END
/*
单例 XMDataBase.m
*/
#import "XMDataBase.h"
#import "FMDB/FMDB.h"
@interface XMDataBase()
{
FMDatabase *db_;
}
@end
@implementation XMDataBase
+ (instancetype)shareInstance {
static XMDataBase *dataBase = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dataBase = [[super allocWithZone:nil] init];
[dataBase initDataBase];
});
return dataBase;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [XMDataBase shareInstance];
}
- (id)copy {
return [XMDataBase shareInstance];
}
- (id)mutableCopy {
return [XMDataBase shareInstance];
}
- (void)initDataBase {
//document路径
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//创建文件路径
NSString *filePath = [documentPath stringByAppendingPathComponent:@"people.sqlite"];
//创建对应路径下的数据库
db_ = [FMDatabase databaseWithPath:filePath];
//打开数据库
if ([db_ open]) {
NSLog(@"打开数据库成功");
//创建表
NSString *creatSql = @"CREATE TABLE IF NOT EXISTS t_people(id integer NOT NULL, name text NOT NULL,age integer NOT NULL)";
if ([db_ executeUpdate:creatSql]) {
NSLog(@"创建数据表t_people成功");
}else {
NSLog(@"创建数据表t_people失败");
}
[db_ close];
}else {
NSLog(@"打开数据库失败");
}
}
#pragma mark 增
- (BOOL)addPerson:(PeopleModel *)person {
[db_ open];
NSString *insertSql = @"INSERT INTO t_people(id,name,age) VALUES(?,?,?)";
BOOL result = [db_ executeUpdate:insertSql,@(person.ID),person.name,@(person.age)];
[db_ close];
return result;
}
#pragma mark 删
- (BOOL)deletePersonWithID:(NSInteger)ID {
[db_ open];
NSString *deleteSql = @"DELETE FROM t_people WHERE id=?";
BOOL result = [db_ executeUpdate:deleteSql,@(ID)];
[db_ close];
return result;
}
#pragma mark 改
- (BOOL)updatePerson:(PeopleModel *)person {
[db_ open];
NSString *updateSql = @"UPDATE t_people SET %@ = ? WHERE id = ?";
BOOL resultName = [db_ executeUpdate:[NSString stringWithFormat:updateSql,@"name"],person.name,@(person.ID)];
BOOL resultAge = [db_ executeUpdate:[NSString stringWithFormat:updateSql,@"age"],@(person.age),@(person.ID)];
[db_ close];
return resultName&&resultAge;
}
#pragma mark 查(获取整张表)
- (NSArray *)getAllPeople {
[db_ open];
NSMutableArray *allPeople = [NSMutableArray array];
NSString *selectSql = @"SELECT *FROM t_people";
FMResultSet *resultSet = [db_ executeQuery:selectSql];
while ([resultSet next]) {
PeopleModel *peopleModel = [[XMPeopleModel alloc] init];
peopleModel.ID = [resultSet intForColumn:@"ID"];
peopleModel.name = [resultSet objectForColumn:@"name"];
peopleModel.age = [resultSet intForColumn:@"age"];
[allPeople addObject:peopleModel];
}
[db_ close];
return allPeople;
}
#pragma mark 查(根据条件查询)
- (XMPeopleModel *)getPersonWithID:(NSInteger)ID {
[db_ open];
NSString *selectSql = @"SELECT *FROM t_people WHERE id = ?";
FMResultSet *resultSet = [db_ executeQuery:selectSql,@(ID)];
while ([resultSet next]) {
NSInteger resultID = [resultSet intForColumn:@"id"];
if (ID == resultID) {
PeopleModel *person = [[XMPeopleModel alloc] init];
person.ID = ID;
person.name = [resultSet objectForColumn:@"name"];
person.age = [resultSet intForColumn:@"age"];
[db_ close];
return person;
}
}
[db_ close];
return nil;
}
#pragma mark 销毁表
- (BOOL)dropTable:(NSString *)tableName {
[db_ open];
NSString *dropSql = @"DROP TABLE IF EXISTS t_people";
BOOL result = [db_ executeUpdate:dropSql];
[db_ close];
return result;
}
@end
/*
XMDataBase单例使用示例
*/
PeopleModel *amy = [[PeopleModel alloc] init];
amy.ID = 2;
amy.name = @"Amy";
amy.age = 18;
BOOL addResult = [[XMDataBase shareInstance] addPerson:amy];
if (addResult) {
NSLog(@"Amy添加成功");
}else{
NSLog(@"Amy添加失败");
}
BOOL deleteResult = [[XMDataBase shareInstance] deletePersonWithID:2];
if (deleteResult) {
NSLog(@"删除Amy成功");
}else{
NSLog(@"删除Amy失败");
}
amy.age = 19;
BOOL updateResult = [[XMDataBase shareInstance] updatePerson:amy];
if (updateResult) {
NSLog(@"Amy的age更新成功");
}else{
NSLog(@"Amy的age更新失败");
}
//根据条件(ID)获取表中特定数据
PeopleModel *Amy = [[XMDataBase shareInstance] getPersonWithID:2];
NSLog(@"name:%@ age:%ld id:%ld",Amy.name,Amy.age,Amy.ID);
//获取整张表
NSArray *arr = [[XMDataBase shareInstance] getAllPeople];
for (PeopleModel *model in arr) {
NSLog(@"name:%@ age:%ld id:%ld",model.name,model.age,model.ID);
}
BOOL dropResult = [[XMDataBase shareInstance] dropTable:@"t_people"];
if (dropResult) {
NSLog(@"删除t_people表成功");
}else{
NSLog(@"删除t_people表失败");
}
日常开发使用心得整理,如有纰漏,欢迎指正!!!