之前有文章简单介绍了怎样在Settings程序中设置自己的程序,并实现保存,使得下次运行自己的程序时显示的还是上次的设置 项。而文章沙盒SandBox的结构介绍SandBox时,我们看到其实使用Settings程序设置后,数据是保存在一个plist文件的。
想要永久保存数据,我们当然可以使用plist文件,当退出程序时,我们执行将数据写入plist文件的操作,使用writeToFile:atomically:方法。
具有这个方法的类有:
NSArray
NSMutableArray
NSDictionary
NSMutableDictionary
NSData
NSMutableData
NSString
NSMutableString
NSNumber
NSDate
例如,我们的数据存储在NSArray的一个对象array中,保存数据时执行:
[arraywriteToFile:filePathatomically:YES];
其中filePath是放在SandBox中的一个plist文件的完整路径。
不过,使用plist文件还是有局限性的,例如,我们不好将一个图片存储在plist中。
这次的小例子中,我们将会通过归档实现数据的保存。当程序运行时,先检查归档文件是否存在,如果存在的话就从归档文件中读取数据显示在界面上;如果归档文件不存在,就使用默认设置。当程序关闭时,会将数据存储在归档文件中,这样下次运行程序时就会显示上次的设置了。
1、运行Xcode 4.3,新建一个Single View Application,名称为:Archiving Test:
然后将准备好的两张图片添加到工程中。
2、先进行界面设计:
单击ViewController.xib,向其中添加控件:
然后向ViewController.h中为控件建立Outlet映射和Action映射,具体是为所有的TextField、ImageView、UISlider控件和UISwitch控件建立Outlet映射,为Button建立Action映射:
3、新建一个类,用于存储我们的数据:
在菜单栏依次选择File — New — File…,在打开的窗口选择Objective-C Class:
单击Next,输入类名:ArchivingData,选择super class为NSObject:
单击Next,选好位置和分组,点击创建,完成类的建立。
4、打开ArchivingData.h,向其中添加属性,以及协议:
#import<Foundation/Foundation.h>
@interfaceArchivingData:NSObject<NSCoding,NSCopying>
@property(copy,nonatomic)UIImage*image;
@property(copy,nonatomic)NSString*name;
@property(copy,nonatomic)NSString*gender;
@property(copy,nonatomic)NSString*vocation;
@property(copy,nonatomic)NSString*page;
@propertyfloattheSlider;
@propertyBOOLisSwitchOn;
@end
5、打开ArchivingData.m,向其中添加代码:
5.1 在@implementation之前添加代码:
#definekImageKey@"ImageKey"
#definekNameKey@"NameKey"
#definekGenderKey@"GenderKey"
#definekVocationKey@"VocationKey"
#definekPageKey@"PageKey"
#definekTheSliderKey@"TheSliderKey"
#definekIsSwitchOn@"IsSwitchOnKey"
5.2 在@implementation之后添加代码:
@synthesizeimage;
@synthesizename;
@synthesizegender;
@synthesizevocation;
@synthesizepage;
@synthesizetheSlider;
@synthesizeisSwitchOn;
5.3 在@end之前添加代码:
#pragmamarkNSCoding
-(void)encodeWithCoder:(NSCoder*)aCoder{
[aCoderencodeObject:imageforKey:kImageKey];
[aCoderencodeObject:nameforKey:kNameKey];
[aCoderencodeObject:genderforKey:kGenderKey];
[aCoderencodeObject:vocationforKey:kVocationKey];
[aCoderencodeObject:pageforKey:kPageKey];
[aCoderencodeFloat:theSliderforKey:kTheSliderKey];
[aCoderencodeBool:isSwitchOnforKey:kIsSwitchOn];
}
-(id)initWithCoder:(NSCoder*)aDecoder{
if(self=[superinit]){
image=[aDecoderdecodeObjectForKey:kImageKey];
name=[aDecoderdecodeObjectForKey:kNameKey];
gender=[aDecoderdecodeObjectForKey:kGenderKey];
vocation=[aDecoderdecodeObjectForKey:kVocationKey];
page=[aDecoderdecodeObjectForKey:kPageKey];
theSlider=[aDecoderdecodeFloatForKey:kTheSliderKey];
isSwitchOn=[aDecoderdecodeBoolForKey:kIsSwitchOn];
}
returnself;
}
5.4 在@end之前添加代码:
#pragmamarkNSCoping
-(id)copyWithZone:(NSZone*)zone{
ArchivingData*copy=[[[selfclass]allocWithZone:zone]init];
copy.image=self.image;
copy.name=[self.namecopyWithZone:zone];
copy.gender=[self.gendercopyWithZone:zone];
copy.vocation=[self.vocationcopyWithZone:zone];
copy.page=[self.pagecopyWithZone:zone];
copy.theSlider=self.theSlider;
copy.isSwitchOn=self.isSwitchOn;
returncopy;
}
在ArchivingData类中,我们添加了几个属性,这些属性与上面创建的控件是一一对应的。之后实现了几个协议方法,这些方法分别用于编码、解码和复制。
别走开,下页内容更劲爆!
6、打开ViewController.h,向其中添加属性和方法:
@property(copy,nonatomic)NSString*archivingFilePath;
-(void)applicationWillResignActive:(NSNotification*)notification;
7、打开ViewController.m,添加代码:
7.1 在@implementation之后添加代码:
@synthesizearchivingFilePath;
7.2 在#import之后添加代码:
#import"ArchivingData.h"
#definekArchivingFileKey@"archivingFile"
#definekArchivingDataKey@"ArchivingDataKey"
7.3 在viewDidLoad方法中添加代码:
-(void)viewDidLoad
{
[superviewDidLoad];
NSArray*paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentsDirectory=[pathsobjectAtIndex:0];
self.archivingFilePath=[documentsDirectorystringByAppendingPathComponent:kArchivingFileKey];
NSFileManager*fileManager=[NSFileManagerdefaultManager];
if([fileManagerfileExistsAtPath:self.archivingFilePath]){
NSData*data=[[NSMutableDataalloc]initWithContentsOfFile:self.archivingFilePath];
NSKeyedUnarchiver*unarchiver=[[NSKeyedUnarchiveralloc]initForReadingWithData:data];
ArchivingData*archivingData=[unarchiverdecodeObjectForKey:kArchivingDataKey];
[unarchiverfinishDecoding];
theImageView.image=archivingData.image;
nameTextField.text=archivingData.name;
genderTextField.text=archivingData.gender;
vocationTextField.text=archivingData.vocation;
pageTextField.text=archivingData.page;
theSlider.value=archivingData.theSlider;
theSwitch.on=archivingData.isSwitchOn;
}else{
theImageView.image=[UIImageimageNamed:@"boy.png"];
}
UIApplication*app=[UIApplicationsharedApplication];
[[NSNotificationCenterdefaultCenter]addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:app];
}
7.4 找到switchImage方法,添加代码:
-(IBAction)switchImage:(id)sender{
UIImage*image1=[UIImageimageNamed:@"boy.png"];
UIImage*image2=theImageView.image;
if(![image1isEqual:image2]){
theImageView.image=image1;
}else{
theImageView.image=[UIImageimageNamed:@"gemini.png"];
}
}
7.5 在@end之前添加代码:
-(void)applicationWillResignActive:(NSNotification*)notification{
ArchivingData*archivingData=[[ArchivingDataalloc]init];
archivingData.image=self.theImageView.image;
archivingData.name=self.nameTextField.text;
archivingData.gender=self.genderTextField.text;
archivingData.vocation=self.vocationTextField.text;
archivingData.page=self.pageTextField.text;
archivingData.theSlider=theSlider.value;
archivingData.isSwitchOn=theSwitch.on;
NSMutableData*data=[[NSMutableDataalloc]init];
NSKeyedArchiver*archiver=[[NSKeyedArchiveralloc]initForWritingWithMutableData:data];
[archiverencodeObject:archivingDataforKey:kArchivingDataKey];
[archiverfinishEncoding];
[datawriteToFile:self.archivingFilePathatomically:YES];
}
8、最后,为了使得键盘可以关闭,我们还要添加关闭键盘的操作,参考《iOS开发4:关闭键盘》中的第2步。
9、运行程序
刚运行程序如下左图:
我们添加一些数据,更换头像,再调整Silder和Switch,如上图右。
之后,按模拟器上的Home建,使得程序在后台运行。
此时,查看程序的SandBox,可以看到程序的Documents目录下出现了文件archivingFile:
之后使用Xcode结束运行,再运行程序。程序第二次运行时,显示如上图左,这说明我们实现了数据的永久存储。