Plist文件(属性列表)是将某些特定的类,通过XML文件的方式保存在目录中。
什么是 XML?
可扩展标记语言 (XML) 允许您以可共享的方式定义和存储数据。XML 支持计算机系统(如网站、数据库和第三方应用程序)之间的信息交换。预定义的规则简化了在任何网络上以 XML 文件的形式传输数据的过程,接收者可以使用这些规则准确高效地读取数据。
我们以 Xcode自动生成的plist文件为例,观察其结构,当我们新建一个项目时后,会发现有一个Info.plist文件,里面有很多参数和配置:
这是Xcode为我们自动生成的plist文件,用来保存当前项目的一些配置,Xcode为ta集成了很多预置的Key
和Value
右键Info.plist文件->Open As->Source Code,用文本编辑器打开plist文件:
可以看到plist文件就是一个XML文件,key
为键,string
为对应的值
可以发现每一个键值对中间都有一个Type
,不难理解这就是value的类型,右键查看:
plist文件可以被序列化的类型(可以被存储的类型)只有这几种:基本数据类型(NSString
、NSNumber
、NSDate
、BOOL
),对象数据类型(NSData/NSMutableData
),集合类型(NSArray/NSMutableArray
、NSDictionary/NSMutableDictionary
),不能保存自定义对象
不难理解,这些数据可以被转换保存到一个纯文本文件(区别于二进制文件)中
1. 读取
一般情况下,plist文件
存储在沙盒的 /Documents中,所以要获取某个plist文件,只需要知道其文件名即可。用过以下方法获取plist数据(一般以NSArray或NSDictionary的形式保存):
//获取文件路径
NSString* path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString* fileName = [path stringByAppendingPathComponent: @"filename.plist"];
//提取plist数据
NSArray* result = [NSArray arrayWithContentsOfFile: fileName];
NSLog(@"%@", result);
2. 存储
往plist文件写入数据直接用相应类型的writeToFile:
方法即可
NSArray* array = @[@"ott", @"123", @"abc"];
[array writeToFile: fileName atomically: YES];
writeToFile: atomically:
方法中atomically
表示是否需要先写入一个辅助文件,再把辅助文件拷贝到目标文件地址,更安全的写入文件,一般该值为YES
运行后,Documents目录:
array以XML格式保存在本地
这个方法也可用于其他数据文件(.plist
、.txt
、.data
等格式的文件),在沙盒中指定某一路径,新建并将数据文件保存在这一路径(同样,自定义对象是不能直接存入的,但是可以通过归档存为.data
文件)
Perference(偏好设置)顾名思义就是专门用来存储系统的偏好配置、用户设置的参数和App的状态等少量信息的,一般不保存其他数据
使用NSUserDefaults
类,以字典形式保存数据,iOS会自动把字典中的键值对转换成对应的XML文件(也就是plist文件),该文件存放在沙盒的 /Library/Preferences/ 目录下
NSUserDefaults
是单例类,此类实际上就是对plist文件操作进行了封装,更方便我们直接操作
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject: @"3G!!!" forKey: @"obj"];
[userDefaults setBool: YES forKey: @"isMale"];
[userDefaults setInteger: 20 forKey: @"age"];
[userDefaults synchronize];
如果没有调用synchronize
方法,系统会根据I/O情况(读取、写入和更新)不定时刻地将数据保存到文件中(以周期性间隔自动调用的同步方法使内存中的缓存与用户的默认数据库保持同步,而不是及时写入的),所以为防止在写完NSUserDefaults
后程序退出导致数据丢失,需要立即写入文件的话就必须调用synchronize
方法
NSString* userName = [userDefaults objectForKey: @"obj"];
BOOL genderIsMale = [userDefaults boolForKey: @"isMale"];
NSInteger age = [userDefaults integerForKey: @"age"];
NSLog(@"%@ %d %ld", userName, genderIsMale, age);
[userDefaults removeObjectForKey: @"isMale"];
这样就会将所有数据保存到同一个文件中(即Preference目录下的一个以此应用包名称来命名的plist文件):
注:
返回值从NSUserDefaults是不可改变的,即使设置一个值可变对象。 例如,如果设置一个可变的字符串值作为"MyStringDefault",则稍后使用stringForKey:检索的字符串将是不可变的
NSUserDefaults除了保存和读取功能外,还为我们提供了一个很便捷的方法:registerDefaults:
ta的参数是一个字典类型,作用仅仅是为了定义一组默认的数据,这些默认的数据是不会被保存到plist文件中的,我们需要手动变更这些数据然后保存
举一个例子,我们可以使用这个方法来确认App是否是第一次启动:
//注册一个默认值
[userDefaults registerDefaults: @{@"firstRun" : @YES}];
//第一次启动还没有生成plist文件,就会读取上面注册的默认值
BOOL isFirstRun = [userDefaults boolForKey: @"firstRun"];
//是第一次启动
if (isFirstRun) {
NSLog(@"这是第一次启动");
//手动改为NO,保存到plist文件中
[userDefaults setBool: NO forKey: @"firstRun"];
} else {
NSLog(@"不是第一次启动");
}
再次强调,registerDefaults
方法中的字典数据是不会保存到plist文件中的,当我们读取某个键值时,如果没有plist文件或plist文件中没有找到对应的键值,那么就会从registerDefaults
方法的字典参数中寻找对应的键值,拿到默认值。
当我们做了相应处理后,再手动把这个键值内容保存到plist中,下次读取就会是直接读取plist文件中的键值,而不是读取registerDefaults
中参数的字典内容了