iOS開發23:經過歸檔永久存儲數據

以前一篇文章《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結束運行,再運行程序。程序第二次運行時,顯示如上圖左,這說明咱們實現了數據的永久存儲。

相關文章
相關標籤/搜索