IOS中数据的持久化保存这块内容,类似于Android中文件的几种常见的存储方式。
对于数据的持久化存储,ios中一般提供了4种不同的机制。
1.属性列表
2.对象归档
3.数据库存储(SQLite3)
4.苹果公司提供的持久性工具Core Data。

其实储存的形式无非就这么几种,而我们还必须要关心的是,这些文件会被放置在那个文件下,然后如何读取。
也就是说:IOS上数据存储,我们要了解的两点,数据存储格式(也就是存储机制),数据存储位置。
1》文件如何存储(如上面4点)
2》文件存储在哪里。
对于数据的操作,其实我们关心的是操作的速率。
就好比在Adnroid中偏好存储,数据库存储,io存储一样。
我大致问了我们公司新来的ios哥们,他说他们培训机构基本对数据操作这块就讲了属性列表和数据库,以及普通的文件存储(比如音视频图这些多媒体数据)。
我就只好先看看书了。

一:应用文件目录
首先我们来看了解下ios数据存储位置,因为只有知道位置路径我们才能去读取数据,而数据的持久化机制不过是针对操作速率来考虑的,
比如我们大致知道属性列表(既键值对形式)的存储熟虑应该高于数据库高于io文件流存储。
我们在选择用何种机制存储数据,主要也是看数据的形式。

一个ios应用安装后大致会有如下文件夹及其对应路径:

%title插图%num

在mac上看模拟器中应用路径:
/Users/nono/Library/Application Support/iPhone Simulator/5.1/Applications/2D135859-1E80-4754-B36D-34A53C521DE3

你在finder中的home下可能找不到Library这个目录,因为貌似是影藏起来了(我这机器上是,在终端可以看到)。
*后那一窜的类似序列号的东西就是ios自动给应用生成的一组应用唯一识别码*为了应用的home目录名。
其下面就是上图所示了。
书上对这些文件夹介绍:

Document:应用程序将其数据存储在这个文件夹下,基于NSUserDefaults的首选项的设置除外。

简单理解是,基本上我们要操作的一些数据都是存储在这个文件夹下面的

TIPS:这边提下一点,对于ios系统这么分配文件夹,是因为在设备进行同步时,ITunes有选择性的意识来备份文件。

比如我们可以猜到,tmp下的应该就不会备份了。

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

[cpp] view plain copy

  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  2.    NSString *docPath = [paths objectAtIndex:0];
  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  2. NSString *docPath = [paths objectAtIndex:0];

Library:基于NSUserDefault首选项设置存储在其下Preferences文件夹中,简单来说,这个文件夹一般你很少操作到。

书上对于这部分基本没介绍。估计对于初级部分是跳过了。

Tmp:应用临时存储文件,当不需要时,应用负责删除其下的文件数据。

该文件也提供了目录获取方法:

[cpp] view plain copy

  1. NSString *tmpDoc = NSTemporaryDirectory();
NSString *tmpDoc = NSTemporaryDirectory();

应用程序文件:这个基本没提到书上,但是我们大致可以猜测,这就是整个应用程序的程序文件夹吧。

好了,以上我们大致解决了我们提到的*个点,文件存储目录

二:数据存储机制

1.属性列表

这个其实我们早见过,plist就是,感觉用来存储键值对小数据是*合适,因为速率很高。

这个存储机制很简单,对于前面我们使用过了在plist文件来读取数据填充一些列表,只不过那会plist文件存储位置不同,

用的是Mainbundle什么的来返回文件夹,其实这边我也推测,上面提到有个应用程序文件夹,它下面的文件就是这么来读取的~(反正暂时不管他)

这边不过就是改变了存储位置,数据操作还是一样的

[cpp] view plain copy

  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  2. NSString *docPath = [paths objectAtIndex:0];
  3. NSString *myFile = [docPath stringByAppendingPathComponent:@“my.list”];
  4. //读取文件 
  5. NSArray *array = [[NSArray alloc] initWithContentsOfFile:myFile];
  6. //操作完若修改了数据则,写入文件 
  7. [array writeToFile:myFile atomically:YES];
  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  2. NSString *docPath = [paths objectAtIndex:0];
  3. NSString *myFile = [docPath stringByAppendingPathComponent:@“my.list”];
  4. //读取文件
  5. NSArray *array = [[NSArray alloc] initWithContentsOfFile:myFile];
  6. //操作完若修改了数据则,写入文件
  7. [array writeToFile:myFile atomically:YES];

2.对象归档

上面的属性列表存储机制,我们都知道,这个机制支持NSArray,NSDictionary,NSData,NSString,NSNumber,NSDate 等等

这些对象直接写入plist文件中。

那么对于一些复杂对象,我要保存整个这个对象数据呢?

反正我是这么觉得,这个机制很像java中的对象整体序列化。当然,这些数据在读取是就需要遵循一种墨守成规的协议了。

首先我们定义的对象类,必须实现NSCoding和NSCopying协议(额,网上说后面这个不实现也可以,我猜是他对象没有copy操作,因此没出错)书本上反正是实现了这两个协议
然后归档中用到的操作类
NSKeyedArchiver
这边我们定义一个对象,h文件中定义两属性,申明要实现的NSCoding和NSCopying协议
实现文件

[cpp] view plain copy

  1. // 
  2. //  TestObj.m 
  3. //  DataStorageTest 
  4. // 
  5. //  Created by Nono on 12-5-12. 
  6. //  Copyright (c) 2012年 NonoWithLilith. All rights reserved. 
  7. // 
  8. #import “TestObj.h” 
  9. @implementation TestObj
  10. @synthesize stringA = stringA;
  11. @synthesize stringB = stringB;
  12. #pragma mark – 
  13. #pragma NSCoding协议实现实现 
  14. – (void)encodeWithCoder:(NSCoder *)aCoder
  15. {   //encoder 
  16.     [aCoder encodeObject:stringAforKey:@“1”];
  17.     [aCoder encodeObject:stringBforKey:@“2”];
  18. }
  19. – (id)initWithCoder:(NSCoder *)aDecoder
  20. {
  21.     //decoder 
  22.     if (self = [superinit]) {
  23.         stringA = [[aDecoder decodeObjectForKey:@“1”] retain];
  24.         stringB = [[aDecoder decodeObjectForKey:@“2”] retain];
  25.     }
  26.     returnself;
  27. }
  28. #pragma NSCopying协议实现 
  29. – (id)copyWithZone:(NSZone *)zone
  30. {
  31.     TestObj *copy = [[[selfclass] allocWithZone:zone] init];
  32.     copy.stringA = [[self.stringAcopyWithZone:zone] autorelease];
  33.     copy.stringB = [[self.stringBcopyWithZone:zone] autorelease];
  34.     return copy;
  35. }
  36. @end
  1. //
  2. // TestObj.m
  3. // DataStorageTest
  4. //
  5. // Created by Nono on 12-5-12.
  6. // Copyright (c) 2012年 NonoWithLilith. All rights reserved.
  7. //
  8. #import “TestObj.h”
  9. @implementation TestObj
  10. @synthesize stringA = stringA;
  11. @synthesize stringB = stringB;
  12. #pragma mark –
  13. #pragma NSCoding协议实现实现
  14. – (void)encodeWithCoder:(NSCoder *)aCoder
  15. { //encoder
  16. [aCoder encodeObject:stringAforKey:@“1”];
  17. [aCoder encodeObject:stringBforKey:@“2”];
  18. }
  19. – (id)initWithCoder:(NSCoder *)aDecoder
  20. {
  21. //decoder
  22. if (self = [superinit]) {
  23. stringA = [[aDecoder decodeObjectForKey:@“1”] retain];
  24. stringB = [[aDecoder decodeObjectForKey:@“2”] retain];
  25. }
  26. returnself;
  27. }
  28. #pragma NSCopying协议实现
  29. – (id)copyWithZone:(NSZone *)zone
  30. {
  31. TestObj *copy = [[[selfclass] allocWithZone:zone] init];
  32. copy.stringA = [[self.stringAcopyWithZone:zone] autorelease];
  33. copy.stringB = [[self.stringBcopyWithZone:zone] autorelease];
  34. return copy;
  35. }
  36. @end

然后是对对象归档的读取和写入

[cpp] view plain copy

  1. //读取归档文件 
  2.    NSData *data = [[NSMutableDataalloc] initWithContentsOfFile:myFile];
  3.    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiveralloc] initForReadingWithData:data];
  4.    TestObj * test = [unarchiver decodeObjectForKey:@“data”];
  5.    [unarchiver finishDecoding];
  6.    [data release];
  7.    [unarchiver release];
  8.    //写入归档文件 
  9.    NSMutableData *data1 = [[NSMutableDataalloc] init];
  10.    NSKeyedArchiver *archiver = [[NSKeyedArchiveralloc] initForWritingWithMutableData:data1];
  11.    [archiver encodeObject:test forKey:@“data”];
  12.    [archiver finishEncoding];
  13.    [data writeToFile:myFile atomically:YES];
  14.    [data1 release];
  15.    [archiver release];
  16.    [test release];
  1. //读取归档文件
  2. NSData *data = [[NSMutableDataalloc] initWithContentsOfFile:myFile];
  3. NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiveralloc] initForReadingWithData:data];
  4. TestObj * test = [unarchiver decodeObjectForKey:@“data”];
  5. [unarchiver finishDecoding];
  6. [data release];
  7. [unarchiver release];
  8. //写入归档文件
  9. NSMutableData *data1 = [[NSMutableDataalloc] init];
  10. NSKeyedArchiver *archiver = [[NSKeyedArchiveralloc] initForWritingWithMutableData:data1];
  11. [archiver encodeObject:test forKey:@“data”];
  12. [archiver finishEncoding];
  13. [data writeToFile:myFile atomically:YES];
  14. [data1 release];
  15. [archiver release];
  16. [test release];

但是问了下新同事,据说这个用到也是蛮少,至少他目前。
但是,我看了下,觉得这个和Android 中Parcelable
太尼玛像似了

三.数据库存储
和Android一样,ios中也是用了SQLite3这种嵌入式数据库。

这个网上例子是很多了。我这边就大致看下了数据库的打开,

数据库表创建,查询,插入

[cpp] view plain copy

  1.  //数据库操作 
  2.  sqlite3 *database;
  3. // const NSString * dbname = @”mydb” 
  4.  int result;
  5.  //打开一个指定路径的现有的数据库,如果没有则会新建一个db库 
  6.  result =  sqlite3_open([myFile UTF8String], &database);
  7.  if (result != SQLITE_OK) {
  8.      sqlite3_close(database);
  9.  }
  10.  //创建一个db表 
  11.  char *errorMsg;
  12.  NSString *sql_create_table = @“CREATE TABLE IF NOT EXISTS NONOTABLE 省略~~~~~~~~~~~~~”;
  13.  int result1 ;
  14.  //sqlite_exec用了针对sqlite3运行任何不要返回数据的命令,它用于执行更新,插入和删除。简单来说,这个方法执行的都是一些无需返回数据(虽然我们可能获取一个状态值。)。 
  15.  result1 = sqlite3_exec(database, [sql_create_table UTF8String], NULL, NULL, &errorMsg);
  16.  //检索查询操作 
  17.  int result2 ;
  18.  sqlite3_stmt *statment;
  19.  NSString *sql_selected = @“查询语句”;
  20. result2 = sqlite3_prepare_v2(database, [sql_selected UTF8String], -1, &statment, nil);
  21.  if(result2 == SQLITE_OK){
  22.      //单步操作 
  23.      while (sqlite3_step(statment) == SQLITE_ROW) {
  24.          int row = sqlite3_column_int(statment, 0);
  25.          char * rpwData = sqlite3_column_text(statment, 1);
  26.      }
  27.      sqlite3_finalize(statment);
  28.  }
  29.  //绑定变量,既就是插入操作的一种变种,比如我么那上面提到sqlite_exec可以执行插入操作,插入内容直接是写在sql字窜里,但是考虑到字窜涉及到无效的符号以及会一些严重的注入漏洞(比如以前听过的引号符号)。 
  30.  NSString *sql_bind = @“insert into foo value(?,?)”;
  31.  result2 = sqlite3_prepare_v2(database, [sql_selected UTF8String], -1, &statment, nil);
  32.  if(result2 == SQLITE_OK){
  33.      sqlite3_bind_int(statment, 1, 235);
  34.      sqlite3_bind_text(statment, 2, “test”, -1, nil);
  35.            sqlite3_finalize(statment);
  36.  }
  37.  if (sqlite3_step(statment) != SQLITE_DONE)
  38.      NSLog(@“error”);
  39.  sqlite3_finalize(statment);
  40.  sqlite3_close(database);
  1. //数据库操作
  2. sqlite3 *database;
  3. // const NSString * dbname = @”mydb”
  4. int result;
  5. //打开一个指定路径的现有的数据库,如果没有则会新建一个db库
  6. result = sqlite3_open([myFile UTF8String], &database);
  7. if (result != SQLITE_OK) {
  8. sqlite3_close(database);
  9. }
  10. //创建一个db表
  11. char *errorMsg;
  12. NSString *sql_create_table = @“CREATE TABLE IF NOT EXISTS NONOTABLE 省略~~~~~~~~~~~~~”;
  13. int result1 ;
  14. //sqlite_exec用了针对sqlite3运行任何不要返回数据的命令,它用于执行更新,插入和删除。简单来说,这个方法执行的都是一些无需返回数据(虽然我们可能获取一个状态值。)。
  15. result1 = sqlite3_exec(database, [sql_create_table UTF8String], NULL, NULL, &errorMsg);
  16. //检索查询操作
  17. int result2 ;
  18. sqlite3_stmt *statment;
  19. NSString *sql_selected = @“查询语句”;
  20. result2 = sqlite3_prepare_v2(database, [sql_selected UTF8String], -1, &statment, nil);
  21. if(result2 == SQLITE_OK){
  22. //单步操作
  23. while (sqlite3_step(statment) == SQLITE_ROW) {
  24. int row = sqlite3_column_int(statment, 0);
  25. char * rpwData = sqlite3_column_text(statment, 1);
  26. }
  27. sqlite3_finalize(statment);
  28. }
  29. //绑定变量,既就是插入操作的一种变种,比如我么那上面提到sqlite_exec可以执行插入操作,插入内容直接是写在sql字窜里,但是考虑到字窜涉及到无效的符号以及会一些严重的注入漏洞(比如以前听过的引号符号)。
  30. NSString *sql_bind = @“insert into foo value(?,?)”;
  31. result2 = sqlite3_prepare_v2(database, [sql_selected UTF8String], -1, &statment, nil);
  32. if(result2 == SQLITE_OK){
  33. sqlite3_bind_int(statment, 1, 235);
  34. sqlite3_bind_text(statment, 2, “test”, -1, nil);
  35. sqlite3_finalize(statment);
  36. }
  37. if (sqlite3_step(statment) != SQLITE_DONE)
  38. NSLog(@“error”);
  39. sqlite3_finalize(statment);
  40. sqlite3_close(database);

关于更多的,大伙可以自行百度,因为数据库的操作语法太怪异了,书上说是基本是基于c的,本人没学过c。看得有点心烦~

4。Core Data存储机制

大致浏览下基本感觉就是将对象归档搞成了可视化和简单化。

这块内容比较多。网上资料也挺丰富的。

暂时不做介绍了。

总结下:其实对于ios数据存储,*常用和主要要掌握的就是属性列表和数据库,因为两个是出镜率比较高的。

其他可能在数据存明显体现出储优势时,我们会去考虑用另外两种机制。

基础的来说,必须掌握属性列表和sqlite的操作存储。