通過歸檔永久存儲數(shù)據(jù)
之前有文章簡單介紹了怎樣在Settings程序中設(shè)置自己的程序,并實(shí)現(xiàn)保存,使得下次運(yùn)行自己的程序時顯示的還是上次的設(shè)置 項(xiàng)。而文章沙盒SandBox的結(jié)構(gòu)介紹SandBox時,我們看到其實(shí)使用Settings程序設(shè)置后,數(shù)據(jù)是保存在一個plist文件的。
想要***保存數(shù)據(jù),我們當(dāng)然可以使用plist文件,當(dāng)退出程序時,我們執(zhí)行將數(shù)據(jù)寫入plist文件的操作,使用writeToFile:atomically:方法。
具有這個方法的類有:
- NSArray
- NSMutableArray
- NSDictionary
- NSMutableDictionary
- NSData
- NSMutableData
- NSString
- NSMutableString
- NSNumber
- NSDate
例如,我們的數(shù)據(jù)存儲在NSArray的一個對象array中,保存數(shù)據(jù)時執(zhí)行:
- [array writeToFile:filePath atomically:YES];
其中filePath是放在SandBox中的一個plist文件的完整路徑。
不過,使用plist文件還是有局限性的,例如,我們不好將一個圖片存儲在plist中。
這次的小例子中,我們將會通過歸檔實(shí)現(xiàn)數(shù)據(jù)的保存。當(dāng)程序運(yùn)行時,先檢查歸檔文件是否存在,如果存在的話就從歸檔文件中讀取數(shù)據(jù)顯示在界面上;如果歸檔文件不存在,就使用默認(rèn)設(shè)置。當(dāng)程序關(guān)閉時,會將數(shù)據(jù)存儲在歸檔文件中,這樣下次運(yùn)行程序時就會顯示上次的設(shè)置了。
1、運(yùn)行Xcode 4.3,新建一個Single View Application,名稱為:Archiving Test:
然后將準(zhǔn)備好的兩張圖片添加到工程中。
2、先進(jìn)行界面設(shè)計(jì):
單擊ViewController.xib,向其中添加控件:
然后向ViewController.h中為控件建立Outlet映射和Action映射,具體是為所有的TextField、ImageView、UISlider控件和UISwitch控件建立Outlet映射,為Button建立Action映射:
3、新建一個類,用于存儲我們的數(shù)據(jù):
在菜單欄依次選擇File — New — File…,在打開的窗口選擇Objective-C Class:
單擊Next,輸入類名:ArchivingData,選擇super class為NSObject:
單擊Next,選好位置和分組,點(diǎn)擊創(chuàng)建,完成類的建立。
4、打開ArchivingData.h,向其中添加屬性,以及協(xié)議:
- #import <Foundation/Foundation.h>
- @interface ArchivingData : 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;
- @property float theSlider;
- @property BOOL isSwitchOn;
- @end
5、打開ArchivingData.m,向其中添加代碼:
5.1 在@implementation之前添加代碼:
- #define kImageKey @"ImageKey"
- #define kNameKey @"NameKey"
- #define kGenderKey @"GenderKey"
- #define kVocationKey @"VocationKey"
- #define kPageKey @"PageKey"
- #define kTheSliderKey @"TheSliderKey"
- #define kIsSwitchOn @"IsSwitchOnKey"
5.2 在@implementation之后添加代碼:
- @synthesize image;
- @synthesize name;
- @synthesize gender;
- @synthesize vocation;
- @synthesize page;
- @synthesize theSlider;
- @synthesize isSwitchOn;
5.3 在@end之前添加代碼:
- #pragma mark NSCoding
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:image forKey:kImageKey];
- [aCoder encodeObject:name forKey:kNameKey];
- [aCoder encodeObject:gender forKey:kGenderKey];
- [aCoder encodeObject:vocation forKey:kVocationKey];
- [aCoder encodeObject:page forKey:kPageKey];
- [aCoder encodeFloat:theSlider forKey:kTheSliderKey];
- [aCoder encodeBool:isSwitchOn forKey:kIsSwitchOn];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- if (self = [super init]) {
- image = [aDecoder decodeObjectForKey:kImageKey];
- name = [aDecoder decodeObjectForKey:kNameKey];
- gender = [aDecoder decodeObjectForKey:kGenderKey];
- vocation = [aDecoder decodeObjectForKey:kVocationKey];
- page = [aDecoder decodeObjectForKey:kPageKey];
- theSlider = [aDecoder decodeFloatForKey:kTheSliderKey];
- isSwitchOn = [aDecoder decodeBoolForKey:kIsSwitchOn];
- }
- return self;
- }
5.4 在@end之前添加代碼:
- #pragma mark NSCoping
- - (id)copyWithZone:(NSZone *)zone {
- ArchivingData *copy = [[[self class] allocWithZone:zone] init];
- copy.image = self.image;
- copy.name = [self.name copyWithZone:zone];
- copy.gender = [self.gender copyWithZone:zone];
- copy.vocation = [self.vocation copyWithZone:zone];
- copy.page = [self.page copyWithZone:zone];
- copy.theSlider = self.theSlider;
- copy.isSwitchOn = self.isSwitchOn;
- return copy;
- }
在ArchivingData類中,我們添加了幾個屬性,這些屬性與上面創(chuàng)建的控件是一一對應(yīng)的。之后實(shí)現(xiàn)了幾個協(xié)議方法,這些方法分別用于編碼、解碼和復(fù)制。
別走開,下頁內(nèi)容更勁爆!
#p#
6、打開ViewController.h,向其中添加屬性和方法:
- @property (copy, nonatomic) NSString *archivingFilePath;
- - (void)applicationWillResignActive:(NSNotification *)notification;
7、打開ViewController.m,添加代碼:
7.1 在@implementation之后添加代碼:
- @synthesize archivingFilePath;
7.2 在#import之后添加代碼:
- #import "ArchivingData.h"
- #define kArchivingFileKey @"archivingFile"
- #define kArchivingDataKey @"ArchivingDataKey"
7.3 在viewDidLoad方法中添加代碼:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
- self.archivingFilePath = [documentsDirectory stringByAppendingPathComponent:kArchivingFileKey];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- if ([fileManager fileExistsAtPath:self.archivingFilePath]) {
- //如果歸檔文件存在,則讀取其中內(nèi)容,顯示在界面上
- NSData *data = [[NSMutableData alloc] initWithContentsOfFile:self.archivingFilePath];
- NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
- ArchivingData *archivingData = [unarchiver decodeObjectForKey:kArchivingDataKey];
- [unarchiver finishDecoding];
- 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 {
- //如果歸檔文件不存在,則設(shè)置imageView為boy.png
- theImageView.image = [UIImage imageNamed:@"boy.png"];
- }
- //當(dāng)程序進(jìn)入后臺時,將當(dāng)前設(shè)置項(xiàng)寫入歸檔文件
- UIApplication *app = [UIApplication sharedApplication];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(applicationWillResignActive:)
- name:UIApplicationWillResignActiveNotification
- object:app];
- }
7.4 找到switchImage方法,添加代碼:
- - (IBAction)switchImage:(id)sender {
- UIImage *image1 = [UIImage imageNamed:@"boy.png"];
- UIImage *image2 = theImageView.image;
- if (![image1 isEqual:image2]) {
- theImageView.image = image1;
- } else {
- theImageView.image = [UIImage imageNamed:@"gemini.png"];
- }
- }
7.5 在@end之前添加代碼:
- //程序進(jìn)入后臺時,保存設(shè)置
- - (void)applicationWillResignActive:(NSNotification *)notification {
- ArchivingData *archivingData = [[ArchivingData alloc] 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 = [[NSMutableData alloc] init];
- NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
- [archiver encodeObject:archivingData forKey:kArchivingDataKey];
- [archiver finishEncoding];
- [data writeToFile:self.archivingFilePath atomically:YES];
- }
8、***,為了使得鍵盤可以關(guān)閉,我們還要添加關(guān)閉鍵盤的操作,參考《iOS開發(fā)4:關(guān)閉鍵盤》中的第2步。
9、運(yùn)行程序
剛運(yùn)行程序如下左圖:
我們添加一些數(shù)據(jù),更換頭像,再調(diào)整Silder和Switch,如上圖右。
之后,按模擬器上的Home建,使得程序在后臺運(yùn)行。
此時,查看程序的SandBox,可以看到程序的Documents目錄下出現(xiàn)了文件archivingFile:
之后使用Xcode結(jié)束運(yùn)行,再運(yùn)行程序。程序第二次運(yùn)行時,顯示如上圖左,這說明我們實(shí)現(xiàn)了數(shù)據(jù)的***存儲。