不管是在iOS还是Android开发过程中,我们都经常性地需要存储一些状态和数据,比如用户对于App的相关设置、需要在本地缓存的数据等等。根据要存储的的数据的大小、存储性质以及存储类型,在iOS和Android中哪个都有多种存储方式。其中,iOS中的存储方式主要包括以下六类:

  • plist文件(属性列表)
  • preference(偏好设置)
  • NSKeyedArchiver(归档)
  • SQLite 3
  • CoreData
  • 手动存放沙盒

一、沙盒机制

  在研究存储方式之前,我们有必要先研究下这些文件会存储到什么地方去,这就需要我们了解iOS App特有的沙盒机制了。iOS程序默认情况下只能访问程序自己的目录,这个目录被称为“沙盒”,即沙盒其实就是一个App特有的一个文件夹,iOS下每个App都有自己特有的一个沙盒,其结构和目录特性都是一样的。

1.1 沙盒结构

  既然沙盒就是一个文件夹,那就看看里面有什么吧。沙盒的目录结构如下图所示,每个App的沙盒都是由下图所示的四部分组成,每一部分中存放的数据和内容都是有一定的规范和性质的。该目录路径的获取方法是直接通过 NSHomeDirectory() 就得到和应用沙盒的路径。

  此外,每一个App还有一个Bundle目录,即“应用程序包”,该目录下 存放的是应用程序的源文件,包括资源文件和可执行文件。

1.2 沙盒目录特性

  虽然沙盒中有这么多文件夹,但是没有文件夹都不尽相同,都有各自的特性。所以在选择存放目录时,一定要认真选择适合的目录。

  • 应用程序包:存放的是应用程序的源文件,包括资源文件和可执行文件。如果你要仿写某一个App或借用某个App的应用图标,可以在该App的应用程序包中找到其.app结尾的源文件,然后显示报内容即可直接获取到其所有的图标和应用切图。在开发中获取其bundle(应用程序包)路径的方法是:

    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSLog(@"%@", path);
  • Documents: 最常用的目录,iTunes同步该应用时会同步此文件夹中的内容,适合存储重要数据。如果自己存储log数据到本地,一般是保存到该路径下。获取路径下的方法是:
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    NSLog(@"%@", path);
  • Library/Caches: iTunes不会同步此文件夹,适合存储体积大,不需要备份的非重要数据。
    NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSLog(@"%@", path);
  • Library/Preferences: iTunes同步该应用时会同步此文件夹中的内容,通常保存应用的设置信息。
  • tmp:iTunes不会同步此文件夹,系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存应用中的一些临时文件,用完就删除。
    NSString *path = NSTemporaryDirectory();
    NSLog(@"%@", path);

二、存储方式

  在文章的开始已经讲到了,iOS中本地存储的方式一般有6种。下面我们将一个个来进行学习和研究。

2.1 plist文件(属性列表)

  plist文件是将某些特定的类,通过XML文件的方式保存在目录中。可以被序列化的类型只有如下几种:

  • NSArray
  • NSMutableArray
  • NSDictionary
  • NSMutableDictionary
  • NSData
  • NSMutableData
  • NSString
  • NSMutableString
  • NSNumber
  • NSDate

1. 获得文件路径

  项目中plist文件是存储在沙盒的documents中,所以要获取某个plist文件,只需要知道其文件名就可以了,如下方式就好可以获取并读取其中的内容,读取时通过对应类型的方式来获取plist的数据。一般plist中的内容都是以NSArray或NSDictionary的形式保存。
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];
NSArray *result = [NSArray arrayWithContentsOfFile:fileName];

2. 存储

往plist中写内容也非常简单,直接用相应类型的writeToFile方法即可。

NSArray *array = @[@"", @"", @""];
[array writeToFile:fileName atomically:YES]; 

3. 注意

  • 只有以上列出的类型才能使用plist文件存储。

  • 存储时使用writeToFile: atomically:方法。 其中atomically表示是否需要先写入一个辅助文件,再把辅助文件拷贝到目标文件地址。这是更安全的写入文件方法,一般都写YES。

  • 读取时使用arrayWithContentsOfFile:方法

2.2 preference(偏好设置)

  preefrence(偏好设置)顾名思义就是用户在使用过程中对App的一些状态和自定义设置状态的保存,例如App的皮肤样式、游戏时是否屏蔽电话和聊天、界面显示格式等等。一般对于一些基本的用户设置,因为数据量很小,我们可以使用OC语言中的NSUserDefaults类来进行处理。使用方法很简单,只需要调用类中的方法即可。此外,NSUserDefaults 创建的数据其实也是一个plist文件,其中数据保存格式是键值对形式,即NSDictionary形式,该文件存放在沙盒 Library/Preferences/ 目录下,一个以你包名命名的.plist文件。

1. 使用方法

//1.获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中写入内容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger: 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);

2. 注意

  • 偏好设置是专门用来保存应用程序的配置信息的,一般不要在偏好设置中保存其他数据。

  • 如果没有调用synchronize方法,系统会根据I/O情况不定时刻地保存到文件中。所以如果需要立即写入文件的就必须调用synchronize方法。

  • 偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。

2.3  NSKeyedArchiver(归档)

  之前说了,不管是NSUserDefaults 或者是 plist 都不能对自定义的对象进行存储,OC提供了解归档恰好解决这个问题。归档在iOS中是另一种形式的序列化,只要遵循了NSCoding协议的对象都可以通过它实现序列化。由于决大多数支持存储数据的Foundation和Cocoa Touch类都遵循了NSCoding协议,因此,对于大多数类来说,归档相对而言还是比较容易实现的。

1. 遵循NSCoding协议

  NSCoding协议声明了两个方法,这两个方法都是必须实现的。一个用来说明如何将对象编码到归档中,另一个说明如何进行解档来获取一个新对象。

  • 遵循协议和设置属性
  //1.遵循NSCoding协议
@interface Person : NSObject //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"];
}
  •  特别注意

  如果需要归档的类是某个自定义类的子类时,就需要在归档和解档之前先实现父类的归档和解档方法。即 [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法。

2. 使用

  需要把对象归档是调用NSKeyedArchiver的工厂方法 archiveRootObject: toFile: 方法。

 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];
[NSKeyedArchiver archiveRootObject:person toFile:file];

  需要从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile: 即可。

 NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"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];
}

3. 注意

2.4 手动存放沙盒

  手动将数据存放到沙盒,其实就是自己在沙盒的某一个指定路径(第一部分介绍了沙盒各目录路径的获取方式)下新建一个保存数据的文件(.txt、.plist、.data等格式的文件),然后向其中写我们需要保存的数据即可。但是沙盒中只能保存OC中的基本数据,自定义的对象不能直接存入,但是可以通过归档存为.data文件。

  //假设我们需往cache 存入数据,并命名为test的txt格式文件中
NSString *filePath = [cachesDir stringByAppendingPathComponent:@"test.txt"];
NSArray *dic = [[NSArray alloc] initWithObjects:@"test",@"test1" ,nil]; if([dic writeToFile:filePath atomically:YES]){
NSLog(@"存入成功");
}
//取出数据 打印
NSLog(@"%@",[NSArray arrayWithContentsOfFile:filePath]); 

2.5 CoreData

  Core Date是ios3.0后引入的数据持久化解决方案,它是是苹果官方推荐使用的,不需要借助第三方框架。Core Date实际上是对SQLite的封装,提供了更高级的持久化方式。在对数据库操作时,不需要使用sql语句,也就意味着即使不懂sql语句,也可以操作数据库中的数据。

  在各类应用开发中使用数据库操作时通常都会用到 (ORM) “对象关系映射”,Core Data就是这样的一种模式。ORM是将关系数据库中的表,转化为程序中的对象,但实际上是对数据中的数据进行操作。

  在使用Core Data进⾏行数据库存取并不需要手动创建数据库,创建数据库的过程完全由Core Data框架自动完成,开发者需要做的就是把模型创建起来,具体数据库的创建不需要管。简单点说,Core Data实际上是将数据库的创建、表的创建、对象和表的转换等操作封装起来,极大的简化了我们的操作。

  Core Date与SQLite相比较,SQLite比较原始,操作比较复杂,使用的是C的函数对数据库进行操作,但是SQLite可控性更强,并且能够跨平台。

  关于Core Date的具体使用方法参见:IOS 数据存储之 Core Data详解

2.6 SQLite 3

  iOS系统自带Core Data来进行持久化处理,而且Core Data可以使用图形化界面来创建对象,但是Core Data不是关系型数据库,对于Core Data来说比较擅长管理在设备上创建的数据持久化存储用户创建的对象,但是要处理大量的数据时就应该优先选择SQL关系型数据库来存储这些数据。 
  Core Data在后台也是使用SQLite来存储数据的,但是开发人员不能直接访问这些数据,只能通过Core Data提供的API来操作,如果一旦人为的通过SQLite修改这些数据那么使用Core Data再次访问这些数据时就会发生错误。

  SQLite是使用C语言写的开源库,实现了一个自包含的SQL关系型数据库引擎,可以使用SQLite存储操作大量的数据,作为关系型数据库我们可以在一个数据库中建立多张相关联的表来解决大量数据重复的问题。而且SQLite库也针对移动设备上的使用进行了优化。 因为SQLite的接口使用C写的,而且Objective-CC的超集所以可以直接在项目中使用SQLite 

  关于SQLite的详细使用方法详见:iOS开发数据库篇—SQLite的应用

iOS学习——iOS常用的存储方式的更多相关文章

  1. IOS学习:常用第三方库(GDataXMLNode:xml解析库)

    IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...

  2. iOS常用的存储方式介绍

    在iOS App开发过程中经常需要操作一些需要持续性保留的数据,比如用户对于App的相关设置.需要在本地缓存的数据等等.本文针对OC中经常使用的一下存储方式做了个整理. 常用的存储工具/方式: NSU ...

  3. iOS常用的存储方式

    在iOS App开发过程中经常需要操作一些需要持续性保留的数据,比如用户对于App的相关设置.需要在本地缓存的数据等等.本文针对OC中经常使用的一下存储方式做了个整理. 常用的存储工具/方式: NSU ...

  4. 怎样实现IOS开发中的数据存储方式

    iOS 开发中,一般有如下几种数据存储方式.需要根据具体的业务场景,选择 合适的数据存储方式. (1)  用户默认设置 – 这种情况通常不需要用户干预,如游戏通关信息,Video 播放记录,或者 Ap ...

  5. IOS的四种数据存储方式及优劣

    IOS有四种经常使用数据存储方式: 第一种方法:用NSUserDefaults存储配置信息 NSUserDefaults被设计用来存储设备和应用的配置信息.它通过一个工厂方法返回默认的.也是最经常使用 ...

  6. iOS学习——iOS项目Project 和 Targets配置详解

    最近开始学习完整iOS项目的开发流程和思路,在实际的项目开发过程中,我们通常需要对项目代码和资料进行版本控制和管理,一般比较常用的SVN或者Github进行代码版本控制和项目管理.我们iOS项目的开发 ...

  7. iOS学习——iOS原生实现二维码扫描

    最近项目上需要开发扫描二维码进行签到的功能,主要用于开会签到的场景,所以为了避免作弊,我们再开发时只采用直接扫描的方式,并且要屏蔽从相册读取图片,此外还在二维码扫描成功签到时后台会自动上传用户的当前地 ...

  8. iOS学习——iOS视频和推荐网站

    最近有人问有没有iOS学习的相关资料,就简单的把自己的知道的和资源共享一下: 个人感觉iOS开发人才饱和,培训泛滥,个人推荐后台升职空间大和web前端竞争小. [链接][Ronda收集整理]2014年 ...

  9. iOS学习——iOS开发小知识点集合

    在iOS学习和开发过程中,经常会遇到一些很小的知识点和问题,一两句话就可以解释清楚了,这样的知识点写一篇随笔又没有必要,但是又想mark一下,以备不时之需,所以就有了本文.后面遇到一些小的知识点会不断 ...

随机推荐

  1. pytesseract使用

    1.安装pip install pytesseract 2.安装tesseract-ocr,下载地址:https://github.com/UB-Mannheim/tesseract/wiki,我安装 ...

  2. ideal中如何添加几个不同的项目在同一个idea页面显示(同一个窗口显示多个工程)

    今天,我遇到了一个问题,就是同事给了我一些项目,我下载了之后,项目有点多,然后想把这些项目都放到一个里面,所以我就采取了添加module的方式进行添加,首先先看一下我们的四个项目, 我们就想实现在一个 ...

  3. Centos 7 ip查看问题

    centos7已经没有ifconfig功能,现在使用的是命令ip addr查看,如果还是习惯ifconfig使用"yum -y install net-tools"命令进行安装 安 ...

  4. MongoDB优化与一些需要注意的细节

    这里总结下这段时间使用mongo的心得,列出了几个需要注意的地方. 1. 系统参数及mongo参数设置 mongo参数主要是storageEngine和directoryperdb,这两个参数一开始不 ...

  5. ubuntu指令记录

    记录一些指令,便于查看使用. 1.sudo -以其他身份运行命令,预设身份为root. 2.ctrl+alt+T打开终端(命令行窗口) 3.如何判断linux系统是32位还是64位,指令:getcon ...

  6. php接入支付宝的流程

    php接入支付宝的流程写在这里供像我一样的小白参考. 1.首先要有一个创建一个应用(选好自己想要的功能,关于支付的功能,貌似都需要签约) 2.下载SDK&Dome(网址https://doc. ...

  7. 50个PHP程序性能优化的方法

    1. 用单引号代替双引号来包含字符串,这样做会更快一些.因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的" ...

  8. Python函数篇(4)之迭代器与生成器

    1.文件操作的"b模式"(补充) 在上一篇文章中,我在最后一部分写了文件处理的一些方法,但是觉得还是有必要再提一下如下的内容: 像rb.wb.ab这种模式,是以字节的形式操作,需要 ...

  9. Python3使用PyQt5制作简单的画板/手写板

    0.目录 1.前言 2.简单的画板1.0 在定点和移动中的鼠标所在处画一条线 3.简单的画板2.0 在定点和移动中的鼠标所在处画一条线 并将画过的线都保留在窗体上 4.简单的画板3.0 将按住鼠标后移 ...

  10. java 之 迭代器模式(大话设计模式)

    众所周知,java是编程语言中的高级语言,在java的世界里,已经有前辈为我们封装好了各个很好用的框架,工具类等,今天笔者想说的迭代器模式也已经被封装过. 就是我们经常使用的for循环迭代器.或者It ...