IOS---数据持久化

##一、文件管理ios

ios沙盒机制:git

ios应用程序只能在为该程序建立的文件系统中读取文件,不能够去其余地方访问,此区域被称为沙盒,因此全部的非代码文件都要保存在此,例如图像、图标、声音、映像、属性列表、文本文件等。github

  • 每一个应用程序都有本身的存储空间
  • 应用程序不能翻过本身的围墙去访问别的存储空间的内容
  • 应用程序请求的数据都要经过权限检测,假如不符合条件的话,不会被放行。

###1.1 目录结构及获取:sql

沙盒路径目录获取:数据库

NSString *path = NSHomeDirectory();
NSLog(@"%@",path);

默认状况下,每一个沙盒含有3个⽂件夹:Documents, Library 和 tmp。由于应⽤的沙盒机制,应用只能在几个目录下读写文件编程

Documents:苹果建议将程序中创建的或在程序中浏览到的文件数据保存在该⺫录下,iTunes备份和恢复的时候会包括此目录,基于NSUserDefaults的首选项的设置除外。数组

对于Document文件夹目录路径的获取,API提供了这么一种方法:缓存

NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",documents);

Library:存储程序的默认设置或其它状态信息;(iTunes备份和恢复的时候会包含此目录) Library/Caches:存放缓存⽂件,iTunes不会备份此⺫录,此目录下文件不会在应⽤退出删除安全

获取Library目录路径:框架

NSString *library = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",library);

获取缓存目录Caches路径:

NSString *cacher = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"%@",cacher);

tmp:提供一个即时建立临时⽂件的地⽅方。(系统重启后会删除tmp里的全部文件)

获取Tem目录路径:

NSString *tem = NSTemporaryDirectory();
    NSLog(@"%@",tem);

ps:能够用字符串方法拼接一个目录路径,会自动加“/”,示例获取Documents 目录路径:

NSString *docPath = [path stringByAppendingPathComponent:@"Documents"];
    NSLog(@"%@",docPath);

###1.2 文件管理类(NSFileManager):用于管理(增、删、改、查)沙盒目录文件

建立目录

1.建立NSFileManager对象并获取Document路径:

NSFileManager *fileManager = [NSFileManager defaultManager];
- (NSString *)docPath {
    
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

2.在Document目录里面添加一个新的目录路径

NSString *dataPath = [[self docPath] stringByAppendingPathComponent:@"Datas"];

3.使用NSFileManager建立目录,返回的是一个BOOL值

NSError *error = nil;
    BOOL isCreated = [fileManager createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error];
    
    if (isCreated) {
        NSLog(@"建立目录成功");
    } else {        
        NSLog(@"建立目录失败");
    }

建立文件并写入数据,能够写入任意类型的文件,图片,文字,数组等

1.根据获取的路径在里面新建一个路径/文件:

NSString *filePath = [[self docPath] stringByAppendingPathComponent:@"Datas/info.png"];

2.建立须要写入的文件:

// NSString *text = @"这是保存的数据";
    // NSData *data = [text dataUsingEncoding:NSUTF8StringEncoding];
    
    UIImage *image = [UIImage imageNamed:@"足球"];
    NSData *imageData = UIImagePNGRepresentation(image);

3.建立文件:

BOOL isCreated = [fileManager createFileAtPath:filePath contents:imageData attributes:nil];
    
    if (isCreated) {
        NSLog(@"建立成功");      
        NSLog(@"%@",[self docPath]);
    } else {        
        NSLog(@"建立失败");
    }

根据指定的路径移除文件、目录 1.建立须要移除的文件路径:

NSString *filePath = [[self docPath] stringByAppendingPathComponent:@"Datas/info.png"];

2.移除文件:

BOOL isRemoved = [fileManager removeItemAtPath:filePath error:nil];
    
    if (isRemoved) {
        NSLog(@"文件移除成功");
        
    } else {
        NSLog(@"文件移除失败");
    }

3.移动文件: 建立要移动文件路径,和要移动到文件的路径

NSString *filePath = [[self docPath] stringByAppendingPathComponent:@"Datas/info.png"];
    
    NSString *toPath = [[self libPath] stringByAppendingPathComponent:@"足球.png"];
- (NSString *)libPath {
    
    return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
}

移动文件:

BOOL isMoved = [fileManager moveItemAtPath:filePath toPath:toPath error:nil];
    
    if (isMoved) {
        NSLog(@"移动完成");
        NSLog(@"%@",[self docPath]);
    } else {        
        NSLog(@"移动失败");
    }

##二、属性列表

属性列表是一种明文的轻量级存储方式,其存储格式有多种,最常规格式为XML格式。在咱们建立一个新的项目的时候,Xcode会自动生成一个info.plist文件用来存储项目的部分系统设置。plist只能用数组(NSArray)或者字典(NSDictionary)进行读取,因为属性列表自己不加密,因此安全性几乎能够说为零。由于,属性列表正经常使用于存储少许的而且不重要的数据。

使⽤属性列表持久化数据对象很是方便,只要是数组或者字典中包含的对象是特定的 可序列话对象(包括NSArray,NSMutableArray,NSDictionary, NSMutableDictionary,NSData,NSMutableData,NSString,NSMutableString, NSNumber,NSDate),就能够直接经过NSDictionary和NSArray的实例方法将其保存到属性列表或者从属性列表中读取他们。

NSArray类方法:

+ arrayWithContentsOfFile:静态建立工厂方法,用于从属性列表中数据,建立NSArray对象。

获取本地路径的plist文件:

NSArray *infos_ = [NSArray arrayWithContentsOfFile:filePath_array];

- initWithContentsOfFile:构建函数,用于从属性列表中数据,建立NSArray对象。

- writeToFile:atomically:该方法把NSArray对象写入属性列表文件,它的第一个参数是文件名,第二个参数代表是否使用辅助文件:若是是ture,则先写入辅助文件,而后将辅助文件从新命名为目标文件;若是为false,则直接写入目标文件。

- writeToFile:options:error:经过提供写入选项将NSData对象写入文件,options参数是指定数据选项,error参数是返回读取数据的错误。

将数组数据写入plist文件

BOOL isSuccess_2 =  [infos writeToFile:filePath_array atomically:YES];
  
    if (isSuccess_2) {
        NSLog(@"数据写入成功");
    } else {        
        NSLog(@"写入失败");
    }

NSDictionary方法同理。

##2.1 扩展Preference 在程序启动后,系统会自动建立一个NSUserDefaults的单例对象,咱们能够获取这个单例来存储少许的数据,它会将输出存储在.plist格式的文件中。其优势是像字典同样的赋值方式方便简单,但缺点是没法存储自定义的数据。

ps:每次操做后都要数据同步。

得到NSUserDefaults系统提供的plist文件:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

设值:

[userDefaults setObject:@100 forKey:@"id"];
    [userDefaults setBool:YES forKey:@"isLoad"];
    [userDefaults setDouble:3.8408 forKey:@"price"];

数据同步(即便更新数据):

[userDefaults synchronize];

取值:

id value = [userDefaults objectForKey:@"id"];
    NSLog(@"%@",value);

修改:

[userDefaults setObject:@2000 forKey:@"id"];
    [userDefaults synchronize];

##三、对象归档

与属性列表相反,一样做为轻量级存储的持久化方案,数据归档是进行加密处理的,数据在通过归档处理会转换成二进制数据,因此安全性要远远高于属性列表。另外使用归档方式,咱们能够将复杂的对象写入文件中,而且无论添加多少对象,将对象写入磁盘的方式都是同样的。

对一个对象进行完整归档须要知足的条件为:该对象的类必须实现NSCoding协议,并且每一个成员变量都应该是基本数据类型或都是实现NSCoding协议的某个类的实例。

@interface User : NSObject <NSCoding>

@property (nonatomic, copy) NSString *userName;
@property (nonatomic, copy) NSString *password;

归档类NSKeyedArchiver和反归档类NSKeyedUnarchiver总与NSData关联在一块儿。NSData封装了字节数据的缓存类,提供类读写数据的方法,具体以下所示:

dataWithContentsOfFile:他是静态工厂方法,用于从文件读取数据来建立NSData对象,

dataWithContentsOfFile:options:error:它是静态工厂方法,用于从文件读取数据来建立NSData对象,options参数是指定读取数据选项,error参数是返回读取数据的错误。

initWithContentsOfFile:options:error:它是实例构造函数,同上一个方法同样。

writeToFile:options:error:将NSData对象写入文件,atomically参数是否写入辅助文件,NO时数据直接写入目标文件路径,ture时数据写入辅助文件,写入成功后将辅助文件路径更名为目标文件路径。当目标文件已经存在时,atomically设置为false,能够防止系统崩溃所致使旧文件的破坏。

归档(编码保存):将数据以二进制的形式保存,经常使用的NSString、NSArray、NSDictionary.... 能够直接归档保存,由于它们都实现了 <NSCoding> 协议 : NSKeyedArchiver 归档代码:

BOOL isSuccess = [NSKeyedArchiver archiveRootObject:user toFile:filePath];

归档过程是使用NSKeyedArchiver对象归档数据,具体过程为:首先将归档数据写入NSData对象,最后再将NSData对象写入归档文件,反归档过程是从归档文件中读取NSData对象,再利用NSKeyedUnarchiver对象从NSData对象中反归档数据。

归档协议方法实现:

#pragma mark - <NSCoing> 对属性编码和解码
// 编码
- (void)encodeWithCoder:(NSCoder *)aCoder {
    
    [aCoder encodeObject:_userName forKey:@"userName"];
    [aCoder encodeObject:_password forKey:@"password"];
}


// 解码
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
    
    self = [super init];
    if (self ) {       
        self.userName = [aDecoder decodeObjectForKey:@"userName"];
        self.password = [aDecoder decodeObjectForKey:@"password"];
    }
    
    return self;
}

解归档(读取解码): NSKeyedUnarchiver:

id object = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    User *user_ = (User *)object;

##四、SQLite数据库

结构化查询语⾔(Structured Query Language)简称SQL,是⼀一种特殊⺫的的编程语言,是一种数据库查询和程序设计语言,⽤用于存取数据以及查询、更新和管理关系数据库系统。

SQLite的数据类型:

  1. NULL,值是NULL
  2. INTEGER,值是有符号整形,根据值的大⼩以1,2,3,4,6或8字节存放
  3. REAL,值是浮点型值,以8字节IEEE浮点数存放
  4. TEXT,值是文本字符串,使用数据库编码(UTF-8,UTF-16BE或者UTF-16LE)存放 5 BLOB,只是一个数据块,彻底按照输入存放(即没有准换)

SQLite提供是C语言的库,使用的时候调用的API都是函数,这些常⽤用的函数包括数据库的建立打开、语句的预处理、执行、关闭等。

sqlite3: 数据库结构体,至关于数据库类。

sqlite3_stmt: sql语句结构体,至关于SQL语句类。

sqlite3_open(): 建立和打开数据库,返回值等于 SQLITE_OK 表⽰示成功。

sqlite3_exec(): 执⾏非查询sql语句,返回值等于 SQLITE_OK 表示执⾏成功。 sqlite3_prepare_v2(): 预处理sql语句,用于数据查询。

sqlite3_step(): 能够⽤于屡次执行sql语句,要先使⽤预处理,用于数据查询。 sqlite3_bind_text(): 绑定sql语句中 ?号对应的参数。

sqlite3_column_text(): 从sqlite3_step()的结果中获取指定列的数据,包含 int,double等多个。

sqlite3_finalize():销毁前⾯面被sqlite3_prepare()建立的预处理语句sqlite3_stmt,在关闭以前完成。

sqlite3_close():关闭以前打开的数据库,使用完后必须关闭数据库释放资源。

###4.1 导入SQLite系统库

OS中使用SQLite得依赖 libsqlite3.dylib 库,因此使用前先要导入这个库。步骤以下:

点击项目文件 -> TARGETS -> Build Phases -> Link Binary With Librarise -> 点击 + 号,XCode7之后不能直接搜索到libsqlite3.dylib,只能搜到libsqlite3.tbd,须要到指定目录中添加,因此须要以下图操做:

一、点击Add Other

二、快捷键 command + shift + G 前往文件夹,输入/user/lib/libsqlite3.dylib 到达库文件目录。

三、选择libsqlite3.dylib ,OK了。

###4.2 数据库的操做

1.建立数据库,数据库扩展名称为.sqlite,sqlite3_open()函数包含两个参数,第一个为数据库的路径由于参数的类型是 char *类型,全部要用[dataPath UTF8String]进行类型转换,第二个为数据库sqlite3指针的地址。

// 一、建立数据库指针,至关于建立一个数据库对象。
	sqlite3 *_sqlite;

//建立数据库的保存路径
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    NSString *sqlPath = [docPath stringByAppendingPathComponent:@"dbName.sqlite"];
    
    int result = sqlite3_open([sqlPath UTF8String], &_sqlite);
    //若是函数的返回值等于 SQLITE_OK(宏) 表示成功
    if (result == SQLITE_OK) {
        NSLog(@"数据库建立成功,%@",docPath);
}
	//数据库打开失败或者使用完后都要调用sqlite3_close()函数,关闭数据库释放资源。
    sqlite3_close(_sqlite);

2.建立表,sqlite3_exec()执行sql语句函数,包含五个参数,第一个是数据库指针,第二个sql语句(char 类型),第三个回调函数,若是不须要回调就用NULL。第四个回调函数的的第一个参数没有用NULL,第五个错误信息地址 char *类型。

NSString *sql = @"CREATE TABLE IF NOT EXISTS User('userID' TEXT, 'userName' TEXT, 'userAge' INTEGER)";
    
    // sqlite3_exec() 执行 sql语句 函数
    int result = sqlite3_exec(_sqlite,[sql UTF8String],NULL,NULL,NULL);
    
    if (result == SQLITE_OK) {
        
        NSLog(@"建立表成功");
    }

3.添加数据

NSString *userID = @"100012";
    NSString *userName = @"加大对";
    int age = 20;
    
    NSString *sql = [NSString stringWithFormat:@"INSERT INTO User('userID','userName','userAge') VALUES('%@','%@',%d)",userID,userName,age];
    
    // sqlite3_exec() 执行 sql 函数
    int result = sqlite3_exec(_sqlite,[sql UTF8String],NULL,NULL,NULL);
    
    if (result == SQLITE_OK) {
        
        NSLog(@"插入数据成功");
    }

4.添加字段

NSString *columnName = @"userSex TEXT";
    NSString *sql = [NSString stringWithFormat:@"ALTER TABLE User ADD COLUMN %@",columnName];
    
    // sqlite3_exec() 执行 sql 函数
    int result = sqlite3_exec(_sqlite,[sql UTF8String],NULL,NULL,NULL);
    
    if (result == SQLITE_OK) {
        
        NSLog(@"添加字段成功");
    }

5.更新数据

NSString *userSex = @"男";
    NSString *userName = @"电风扇";
    NSString *sql = [NSString stringWithFormat:@"UPDATE User SET userSex = '%@' WHERE userName = '%@'",userSex,userName];
    
    // sqlite3_exec() 执行 sql 函数
    int result = sqlite3_exec(_sqlite,[sql UTF8String],NULL,NULL,NULL);
    
    if (result == SQLITE_OK) {
        
        NSLog(@"修改数据成功成功");
    } else {
        
        NSLog(@"失败");
    }

6.删除数据

NSString *userName = @"电风扇";
    NSString *sql = [NSString stringWithFormat:@"DELETE FROM User WHERE userName = '%@'",userName];
    
    // sqlite3_exec() 执行 sql 函数
    int result = sqlite3_exec(_sqlite,[sql UTF8String],NULL,NULL,NULL);
    
    if (result == SQLITE_OK) {
        
        NSLog(@"删除数据成功");
        
    } else {
        
        NSLog(@"失败");
    }

7.查询数据

//一、建立sql语句结构体指针(能够理解为sql语句对象)
    sqlite3_stmt *_stmt;
    
    // NSString *sql = @"SELECT *FROM User";
    
    NSString *key = @"张";
    NSString *sql = [NSString stringWithFormat:@"SELECT *FROM User WHERE userName LIKE '%%%@%%'",key];
    
    
    // 二、编译查询语句
    int result = sqlite3_prepare_v2(_sqlite,[sql UTF8String],-1,&_stmt,NULL);
    
    if (result == SQLITE_OK) {
        NSLog(@"sql语句编程经过");
        
        NSMutableArray *users = [NSMutableArray array];
        
        // 三、执行查询语句,== SQLITE_ROW 表示还有下一条数据
        while (sqlite3_step(_stmt) == SQLITE_ROW) {
            
            /* 四、获取每一行数据对应的字段(列)
             
             sqlite3_column_text() 对应 TEXT 类型
             sqlite3_column_int() 对应 INTERER类型
             */
            char *userID = (char *)sqlite3_column_text(_stmt,0);
            char *userName = (char *)sqlite3_column_text(_stmt,1);
            int userAge = sqlite3_column_int(_stmt,2);
            char *userSex = (char *)sqlite3_column_text(_stmt,3);
            
            NSString *userID_str = [NSString stringWithUTF8String:userID];
            NSString *userName_str = [NSString stringWithUTF8String:userName];
            NSString *userSex_str = [NSString stringWithUTF8String:userSex];
            
            // 把查询到的数据保存为 model 对象
            User *user = [[User alloc] init];
            user.userID = userID_str;
            user.userName = userName_str;
            user.userSex = userSex_str;
            user.userAge = userAge;
            [users addObject:user];
            
            NSLog(@"%@, %@, %d,%@",userID_str,userName_str,userAge,userSex_str);
            
        }
        
    }

###4.3 第三方框架(FMDB)使用

iOS开发时,项目中会引用许多第三方库,CocoaPods能够用来方便的统一管理这些第三方库,安装方法.

相关文章
相关标签/搜索