IOS---数据持久化

本文介绍了iOS开发中文件管理的基本概念与实践方法,详细解释了沙盒机制下的文件存储目录,如Documents、Library和tmp目录的作用与获取方法。同时,深入探讨了属性列表、对象归档和SQLite数据库三种数据持久化技术的使用细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

##1、文件管理

ios沙盒机制:

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

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

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

沙盒路径目录获取:

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(@"移动失败");
    }

##2、属性列表

属性列表是一种明文的轻量级存储方式,其存储格式有多种,最常规格式为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];

##3、对象归档

与属性列表相反,同样作为轻量级存储的持久化方案,数据归档是进行加密处理的,数据在经过归档处理会转换成二进制数据,所以安全性要远远高于属性列表。另外使用归档方式,我们可以将复杂的对象写入文件中,并且不管添加多少对象,将对象写入磁盘的方式都是一样的。

对一个对象进行完整归档需要满足的条件为:该对象的类必须实现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;

##4、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,需要到指定目录中添加,所以需要如下图操作:

1、点击Add Other

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

3、选择libsqlite3.dylib ,OK了。

###4.2 数据库的操作

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

	// 1、创建数据库指针,相当于创建一个数据库对象。
	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.查询数据

//1、创建sql语句结构体指针(可以理解为sql语句对象)
    sqlite3_stmt *_stmt;
    
    // NSString *sql = @"SELECT *FROM User";
    
    NSString *key = @"张";
    NSString *sql = [NSString stringWithFormat:@"SELECT *FROM User WHERE userName LIKE '%%%@%%'",key];
    
    
    // 2、编译查询语句
    int result = sqlite3_prepare_v2(_sqlite,[sql UTF8String],-1,&_stmt,NULL);
    
    if (result == SQLITE_OK) {
        NSLog(@"sql语句编程通过");
        
        NSMutableArray *users = [NSMutableArray array];
        
        // 3、执行查询语句,== SQLITE_ROW 表示还有下一条数据
        while (sqlite3_step(_stmt) == SQLITE_ROW) {
            
            /* 4、获取每一行数据对应的字段(列)
             
             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可以用来方便的统一管理这些第三方库,安装方法.

转载于:https://my.oschina.net/6603044/blog/740047

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值