不管是在 iOS 还是 Android 开发过程中,我们都经常性地需要存储一些状态和数据,比如用户对于 App 的相关设置、需要在本地缓存的数据等等。根据要存储的的数据的大小、存储性质以及存储类型,在 iOS 和 Android 中哪个都有多种存储方式。其中,iOS 中的存储方式主要包括以下六类:
在研究存储方式之前,我们有必要先研究下这些文件会存储到什么地方去,这就需要我们了解 iOS App 特有的沙盒机制了。iOS 程序默认情况下只能访问程序自己的目录,这个目录被称为 "沙盒",即沙盒其实就是一个 App 特有的一个文件夹,iOS 下每个 App 都有自己特有的一个沙盒,其结构和目录特性都是一样的。
既然沙盒就是一个文件夹,那就看看里面有什么吧。沙盒的目录结构如下图所示,每个 App 的沙盒都是由下图所示的四部分组成,每一部分中存放的数据和内容都是有一定的规范和性质的。该目录路径的获取方法是直接通过 NSHomeDirectory() 就得到和应用沙盒的路径。
此外,每一个 App 还有一个 Bundle 目录,即 "应用程序包",该目录下 存放的是应用程序的源文件,包括资源文件和可执行文件。
虽然沙盒中有这么多文件夹,但是没有文件夹都不尽相同,都有各自的特性。所以在选择存放目录时,一定要认真选择适合的目录。
- NSString * path = [[NSBundle mainBundle] bundlePath];
- NSLog(@"%@", path);
- NSString * path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
- NSLog(@"%@", path);
- NSString * path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
- NSLog(@"%@", path);
- NSString * path = NSTemporaryDirectory();
- NSLog(@"%@", path);
在文章的开始已经讲到了,iOS 中本地存储的方式一般有 6 种。下面我们将一个个来进行学习和研究。
plist 文件是将某些特定的类,通过 XML 文件的方式保存在目录中。可以被序列化的类型只有如下几种:
项目中 plist 文件是存储在沙盒的 documents 中,所以要获取某个 plist 文件,只需要知道其文件名就可以了,如下方式就好可以获取并读取其中的内容,读取时通过对应类型的方式来获取 plist 的数据。一般 plist 中的内容都是以 NSArray 或
- NSDictionary的形式保存。
2. 存储
- NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
- NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
往 plist 中写内容也非常简单,直接用相应类型的 writeToFile 方法即可。
- NSArray *array = @[@"123", @"456", @"789"];
- [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:21 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 //1.遵循NSCoding协议
- 2 @interface Person : NSObject //2.设置属性
- 3 @property (strong, nonatomic) UIImage *avatar;
- 4 @property (copy, nonatomic) NSString *name;
- 5 @property (assign, nonatomic) NSInteger age;
- 6 @end
- 实现协议方法
- 1 //解档
- 2 - (id)initWithCoder:(NSCoder *)aDecoder {
- 3 if ([super init]) {
- 4 self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
- 5 self.name = [aDecoder decodeObjectForKey:@"name"];
- 6 self.age = [aDecoder decodeIntegerForKey:@"age"];
- 7 }
- 8 return self;
- 9 }
- 10 //归档
- 11 - (void)encodeWithCoder:(NSCoder *)aCoder {
- 12 [aCoder encodeObject:self.avatar forKey:@"avatar"];
- 13 [aCoder encodeObject:self.name forKey:@"name"];
- 14 [aCoder encodeInteger:self.age forKey:@"age"];
- 15 }
- 特别注意
- 如果需要归档的类是某个自定义类的子类时,就需要在归档和解档之前先实现父类的归档和解档方法。即 [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法。2. 使用需要把对象归档是调用NSKeyedArchiver的工厂方法 archiveRootObject: toFile: 方法。1 NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
- 2 Person *person = [[Person alloc] init];
- 3 person.avatar = self.avatarView.image;
- 4 person.name = self.nameField.text;
- 5 person.age = [self.ageField.text integerValue];
- 6 [NSKeyedArchiver archiveRootObject:person toFile:file];需要从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile: 即可。1 NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
- 2 Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
- 3 if (person) {
- 4 self.avatarView.image = person.avatar;
- 5 self.nameField.text = person.name;
- 6 self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
- 7 }3. 注意
- 必须遵循并实现NSCoding协议
- 保存文件的扩展名可以任意指定
- 继承时必须先调用父类的归档解档方法
- 扩展:iOS开发基础-数据存储方式(归档)
- 2.4 手动存放沙盒手动将数据存放到沙盒,其实就是自己在沙盒的某一个指定路径(第一部分介绍了沙盒各目录路径的获取方式)下新建一个保存数据的文件(.txt、.plist、.data等格式的文件),然后向其中写我们需要保存的数据即可。但是沙盒中只能保存OC中的基本数据,自定义的对象不能直接存入,但是可以通过归档存为.data文件。1 //假设我们需往cache 存入数据,并命名为test的txt格式文件中
- 2 NSString *filePath = [cachesDir stringByAppendingPathComponent:@"test.txt"];
- 3 NSArray *dic = [[NSArray alloc] initWithObjects:@"test",@"test1" ,nil];
- 4
- 5 if([dic writeToFile:filePath atomically:YES]){
- 6 NSLog(@"存入成功");
- 7 }
- 8 //取出数据 打印
- 9 NSLog(@"%@",[NSArray arrayWithContentsOfFile:filePath]); 2.5 CoreDataCore 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 3iOS系统自带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-C是C的超集所以可以直接在项目中使用SQLite。关于SQLite的详细使用方法详见:iOS开发数据库篇—SQLite的应用
来源: https://www.cnblogs.com/mukekeheart/p/8177410.html