Objective-C 入門指南 - 存檔與讀檔

我們要存檔,儲存的到底是什麼呢?物件 (object) 嗎?屬性 (property) 嗎?還有方法 (method) 呢?




要儲存 Objective-C 的物件,該物件就得實作 NSCoding 協定 (protocol) 。所謂的協定是一個共通的程式規格,凡是協定宣告的方法都需要實作出來,也就是要自己定義方法內容。


由於我們要儲存的是 Encrypt 型態 (type) 的屬性 encrypt ,因此 Encrypt 要先實作 NSCoding ,實作寫法如下
@interface Encrypt: NSObject <NSCoding>


也就是在 @interface 那一行,寫在所繼承的物件之後,我們需要修改 Encrypt.h 中的這一行。


NSCoding 需要實作兩個方法,分別是 encodeWithCoder: 與 initWithCoder:
- (void) encodeWithCoder: (NSCoder *) encoder {
 [encoder encodeObject: cArray forKey: @"cArray"];
}

- (id) initWithCoder: (NSCoder *) decoder {
 cArray = [decoder decodeObjectForKey: @"cArray"];
 
 return self;
}


這裡我們只儲存 Encrypt 型態的 cArray 屬性,因為 cArray 為密碼表,儲存密碼表就可以了。存檔是用 encodeWithCoder: 方法,藉由 NSCoder 型態參數 (parameter) encoder 的 encodeObject:forKey: 方法,以 cArray 作為第一個參數,第二個參數為 key 值,我們這裡用 @"cArray" ,讀檔(載入檔案)則是用 decodeObjectForKey: 方法,提供 key 值當參數,然後將回傳值指派回 cArray 。


我們需要把以上的 encodeWithCoder: 與 initWithCoder: 放入 Encrypt.m 之中,至於標頭檔 Encrypt.h 無須加入 encodeWithCoder: 與 initWithCoder: 的宣告,因為這兩個方法已經宣告在 NSCoding 之中,而 Encrypt 也已實作 NSCoding 了。


現在回到 EncryptController , Encrypt 型態的屬性 encrypt 已經可以被存檔了,我們要來設計 loadEncrypt: 與 saveEncrypt: 。這裡要先講一個觀念。


許多物件導向程式語言 (object-oriented programming language) 遇到無法預期的狀況,就像我們要開啟或儲存指定檔名的檔案,為了預防檔案不存在導致程式發生錯誤,因此這些物件導向程式語言大都提供例外處理 (exception handling) 的機制,檔案不存在的話就發起例外 (exception) 。 Objective-C 的例外處理則是利用 @try 、 @catch 、 @finally 三個指令。


程式中一碰到 @try 的時候,會先執行 @try 的部份看能否順利執行,如果例外發生就跳到 @catch 的地方, @finally 可有可無,因為這是一定會執行的部份。不過例外處理最大的缺點是浪費太多系統資源,降低程式的執行效率,因此 Objective-C 的原則是能不 @try 就不 @try 囉!


我們提供的 loadEncrypt: 與 saveEncrypt: 並不包含 @try 的部份,如下
- (IBAction) loadEncrypt: (id)sender {
    BOOL isFileExist = [[NSFileManager defaultManager] fileExistsAtPath: @"../../encryptor"];
 
    if (isFileExist) {
        encrypt = [NSKeyedUnarchiver unarchiveObjectWithFile: @"../../encryptor"];
        [displayField setStringValue: @"This is Load button. Encrypt object is loaded."];
    }
    else {
        [displayField setStringValue: @"This is Load button. Encrypt object is not loaded."];
    }
}

- (IBAction) saveEncrypt: (id)sender {
    BOOL succeed = [NSKeyedArchiver archiveRootObject: encrypt toFile: @"../../encryptor"];
 
    if (!succeed){
        [displayField setStringValue: @"This is Save button. Encrypt object is not saved."];
    }
    else {
        [displayField setStringValue: @"This is Save button. Encrypt object is saved."];
    }
}


讀檔 loadEncrypt: 是利用 NSFileManager 的 defaultManager ,然後以 fileExistsAtPath: 測試指定路徑 "../../encryptor" 是否存在, encryptor 就是下面 saveEncrypt: 存檔的指定檔名,這樣回傳 YES 或 NO 。 NO 的話就不會進行開啟檔案的動作, YES 的話就利用 NSKeyedUnarchiver 的 unarchiveObjectWithFile: 開啟指定路徑,然後將結果指派給 encrypt 。


存檔 saveEncrypt: 則是直接利用 NSKeyedArchiver 的 archiveRootObject:toFile: 儲存 encrypt 到指定路徑 "../../encryptor" 囉!


好了,這樣就有存檔與讀檔的功能了。我們也已經完成 EncryptController.m ,發展這個編碼與解碼的軟體也告一段落了,下一步是什麼呢?


中英文術語對照
物件object
屬性property
方法method
協定protocol
型態type
參數parameter
物件導向程式語言object-oriented programming language
例外處理exception handling
例外exception


您可以繼續參考
GUI 篇


相關目錄
Objective-C 入門指南
Objective-C 教材
首頁



參考資料
Learning Objective-C: A Primer
The Objective-C Programming Language
Cocoa Fundamentals Guide
Coding Guidelines for Cocoa
Advanced Memory Management Programming Guide
Archives and Serializations Programming Guide

沒有留言: