以前一篇文章《iOS開發20:使用Settings Bundle爲程序添加設置項》中簡單介紹了怎樣在Settings程序中設置本身的程序,並實現保存,使得下次運行本身的程序時顯示的仍是上次的設置項。而上一篇文章介紹SandBox時,咱們看到其實使用Settings程序設置後,數據是保存在一個plist文件的。app
想要永久保存數據,咱們固然可使用plist文件,當退出程序時,咱們執行將數據寫入plist文件的操做,使用writeToFile:atomically:方法。ide
具備這個方法的類有:編碼
NSArray NSMutableArray NSDictionary NSMutableDictionary NSData NSMutableData NSString NSMutableString NSNumber NSDate
例如,咱們的數據存儲在NSArray的一個對象array中,保存數據時執行:atom
[array writeToFile:filePath atomically:YES];
其中filePath是放在SandBox中的一個plist文件的完整路徑。.net
不過,使用plist文件仍是有侷限性的,例如,咱們很差將一個圖片存儲在plist中。設計
此次的小例子中,咱們將會經過歸檔實現數據的保存。當程序運行時,先檢查歸檔文件是否存在,若是存在的話就從歸檔文件中讀取數據顯示在界面上;若是歸檔文件不存在,就使用默認設置。當程序關閉時,會將數據存儲在歸檔文件中,這樣下次運行程序時就會顯示上次的設置了。code
一、運行Xcode 4.3,新建一個Single View Application,名稱爲:Archiving Test:server
而後將準備好的兩張圖片添加到工程中。對象
二、先進行界面設計:blog
單擊ViewController.xib,向其中添加控件:
而後向ViewController.h中爲控件創建Outlet映射和Action映射,具體是爲全部的TextField、ImageView、UISlider控件和UISwitch控件創建Outlet映射,爲Button創建Action映射:
三、新建一個類,用於存儲咱們的數據:
在菜單欄依次選擇File — New — File…,在打開的窗口選擇Objective-C Class:
單擊Next,輸入類名:ArchivingData,選擇super class爲NSObject:
單擊Next,選好位置和分組,點擊建立,完成類的創建。
四、打開ArchivingData.h,向其中添加屬性,以及協議:
#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
五、打開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類中,咱們添加了幾個屬性,這些屬性與上面建立的控件是一一對應的。以後實現了幾個協議方法,這些方法分別用於編碼、解碼和複製。
六、打開ViewController.h,向其中添加屬性和方法:
@property (copy, nonatomic) NSString *archivingFilePath; - (void)applicationWillResignActive:(NSNotification *)notification;
七、打開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]) { //若是歸檔文件存在,則讀取其中內容,顯示在界面上 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 { //若是歸檔文件不存在,則設置imageView爲boy.png theImageView.image = [UIImage imageNamed:@"boy.png"]; } //當程序進入後臺時,將當前設置項寫入歸檔文件 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以前添加代碼:
//程序進入後臺時,保存設置 - (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]; }
八、最後,爲了使得鍵盤能夠關閉,咱們還要添加關閉鍵盤的操做,參考《iOS開發4:關閉鍵盤》中的第2步。
九、運行程序
剛運行程序以下左圖:
咱們添加一些數據,更換頭像,再調整Silder和Switch,如上圖右。
以後,按模擬器上的Home建,使得程序在後臺運行。
此時,查看程序的SandBox,能夠看到程序的Documents目錄下出現了文件archivingFile:
以後使用Xcode結束運行,再運行程序。程序第二次運行時,顯示如上圖左,這說明咱們實現了數據的永久存儲。