一.简单说明
1.在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用,且必须先获取路径相对麻烦。
2.偏好设置(将所有的东西都保存在同一个文件夹下面,且主要用于存储应用的设置信息)。
3.归档:因为前两者都有一个致命的缺陷,只能存储常用的类型。归档可以实现把自定义的对象存储放在文件中。
1.代码示例 DBPerson.h文件
//如果想将一个自定义对象保存到文件中必须实现NSCoding协议 @interface DBPerson : NSObject <NSCoding> //姓名 @property(nonatomic,copy) NSString *name; //年龄 @property(nonatomic,assign) int age; //身高 @property(nonatomic,assign) double height; @end
DBPerson.m文件
#import "DBPerson.h" @implementation DBPerson /** * 1.当将一个自定义对象保存到文件的时候就会调用该方法 * 2.在该方法中说明如何存储自定义对象的属性 * 3.也就说在该方法中说清楚存储自定义对象的哪些属性 */ - (void)encodeWithCoder:(NSCoder *)aCoder{ NSLog(@"调用了encodeWithCoder:方法"); [aCoder encodeObject:self.name forKey:@"name"]; [aCoder encodeInteger:self.age forKey:@"age"]; [aCoder encodeDouble:self.height forKey:@"height"]; } /** * 1.当从文件中读取一个对象的时候就会调用该方法 * 2.在该方法中说明如何读取保存在文件中的对象 * 3.也就是说在该方法中说清楚怎么读取文件中的对象 */ - (id)initWithCoder:(NSCoder *)aDecoder{ NSLog(@"调用了initWithCoder:方法"); if (self = [super init]) { self.name = [aDecoder decodeObjectForKey:@"name"]; self.age = (int)[aDecoder decodeIntegerForKey:@"age"]; self.height = [aDecoder decodeDoubleForKey:@"height"]; } return self; } @end
ViewController.m文件
#import "ViewController.h" #import "DBPerson.h" #define CURRENT_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define CURRENT_SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height - 64) #define BUTTON_WIDTH 80 #define BUTTON_HEIGHT 40 @interface ViewController () //保存数据按钮 @property(nonatomic,strong) UIButton *saveButton; //读取数据按钮 @property(nonatomic,strong) UIButton *readButton; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self initControl]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } //初始化控件 - (void)initControl{ _saveButton = [[UIButton alloc] initWithFrame:CGRectMake(CURRENT_SCREEN_WIDTH/2 - BUTTON_WIDTH/2, CURRENT_SCREEN_HEIGHT/2 - BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT)]; [_saveButton setTitle:@"保存数据" forState:UIControlStateNormal]; [_saveButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [_saveButton addTarget:self action:@selector(saveClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_saveButton]; _readButton = [[UIButton alloc] initWithFrame:CGRectMake(CURRENT_SCREEN_WIDTH/2 - BUTTON_WIDTH/2, _saveButton.frame.origin.y + _saveButton.frame.size.height + 60, BUTTON_WIDTH, BUTTON_HEIGHT)]; [_readButton setTitle:@"读取数据" forState:UIControlStateNormal]; [_readButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [_readButton addTarget:self action:@selector(readClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_readButton]; } #pragma mark -按钮事件 - (void)saveClick{ //创建对象 DBPerson *person = [[DBPerson alloc] init]; person.name = @"文丁丁"; person.age = 31; person.height = 1.76f; //获取文件路径 NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [docPath stringByAppendingPathComponent:@"person.yangyang"]; NSLog(@"path = %@",path); //将自定义的对象保存到文件中 [NSKeyedArchiver archiveRootObject:person toFile:path]; } - (void)readClick{ //获取文件路径 NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [docPath stringByAppendingPathComponent:@"person.yangyang"]; //从文件中读取对象 DBPerson *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; NSLog(@"name = %@",person.name); NSLog(@"age = %d",person.age); NSLog(@"height = %f",person.height); } @end
三.继承类中的使用
DBStudent.h文件
#import "DBPerson.h" @interface DBStudent : DBPerson //增加一个体重属性 @property(nonatomic,assign) double weight; @end
DBStudent.m文件
#import "DBStudent.h" @implementation DBStudent //在子类中重写这两个方法 - (void)encodeWithCoder:(NSCoder *)aCoder{ [super encodeWithCoder:aCoder]; NSLog(@"调用了DBStudent encodeWithCoder"); [aCoder encodeFloat:self.weight forKey:@"weight"]; } - (id)initWithCoder:(NSCoder *)aDecoder{ if (self = [super initWithCoder:aDecoder]) { NSLog(@"调用了DBStudent initWithCoder"); self.weight = [aDecoder decodeFloatForKey:@"weight"]; } return self; } @end
ViewController.m文件
#import "ViewController.h" #import "DBStudent.h" #define CURRENT_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define CURRENT_SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height - 64) #define BUTTON_WIDTH 80 #define BUTTON_HEIGHT 40 @interface ViewController () //保存数据按钮 @property(nonatomic,strong) UIButton *saveButton; //读取数据按钮 @property(nonatomic,strong) UIButton *readButton; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self initControl]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } //初始化控件 - (void)initControl{ _saveButton = [[UIButton alloc] initWithFrame:CGRectMake(CURRENT_SCREEN_WIDTH/2 - BUTTON_WIDTH/2, CURRENT_SCREEN_HEIGHT/2 - BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT)]; [_saveButton setTitle:@"保存数据" forState:UIControlStateNormal]; [_saveButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [_saveButton addTarget:self action:@selector(saveClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_saveButton]; _readButton = [[UIButton alloc] initWithFrame:CGRectMake(CURRENT_SCREEN_WIDTH/2 - BUTTON_WIDTH/2, _saveButton.frame.origin.y + _saveButton.frame.size.height + 60, BUTTON_WIDTH, BUTTON_HEIGHT)]; [_readButton setTitle:@"读取数据" forState:UIControlStateNormal]; [_readButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [_readButton addTarget:self action:@selector(readClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_readButton]; } #pragma mark -按钮事件 - (void)saveClick{ // //创建对象 // DBPerson *person = [[DBPerson alloc] init]; // person.name = @"文丁丁"; // person.age = 31; // person.height = 1.76f; DBStudent *student = [[DBStudent alloc] init]; student.name = @"wendingding"; student.age = 31; student.height = 1.80f; student.weight = 100; //获取文件路径 NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [docPath stringByAppendingPathComponent:@"person.yangyang"]; NSLog(@"path = %@",path); //将自定义的对象保存到文件中 [NSKeyedArchiver archiveRootObject:student toFile:path]; } - (void)readClick{ //获取文件路径 NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [docPath stringByAppendingPathComponent:@"person.yangyang"]; //从文件中读取对象 DBStudent *student = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; NSLog(@"name = %@",student.name); NSLog(@"age = %d",student.age); NSLog(@"height = %f",student.height); NSLog(@"weight = %f",student.weight); } @end
四.重要说明
1.保存数据过程
// //创建对象 // DBPerson *person = [[DBPerson alloc] init]; // person.name = @"文丁丁"; // person.age = 31; // person.height = 1.76f; DBStudent *student = [[DBStudent alloc] init]; student.name = @"wendingding"; student.age = 31; student.height = 1.80f; student.weight = 100; //获取文件路径 NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [docPath stringByAppendingPathComponent:@"person.yangyang"]; NSLog(@"path = %@",path); //将自定义的对象保存到文件中 [NSKeyedArchiver archiveRootObject:student toFile:path];
2.读取数据过程
//获取文件路径 NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; NSString *path = [docPath stringByAppendingPathComponent:@"person.yangyang"]; //从文件中读取对象 DBStudent *student = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; NSLog(@"name = %@",student.name); NSLog(@"age = %d",student.age); NSLog(@"height = %f",student.height); NSLog(@"weight = %f",student.weight);
3.遵守 NSCoding 协议,并实现该协议中的两个方法。
4.如果是继承,则子类一定要重写那两个方法。因为person的子类在存取的时候,会去子类中去找调用的方法,没找到那么它就去父类中找,所以最好保存和读取的时候新增加的属性会被忽略。需要先调用父类的方法,先初始化父类的,在初始化子类的。
5.保存数据的文件的后缀名可以随意命名。
6.通过plist保存的数据是直接显示的,不安全。通过归档方法的数据在文件中打开是乱码的,更安全。