自定義物件若要支援歸檔 (序列化) 必須實現 `NSCoding` 兩個必要方法:
- (void)encodeWithCoder:(NSCoder*)coder:編碼實例變數- (id)initWithCoder:(NSCoder*)coder:解碼並初始化
// Person.h
#import
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *email;
@property (nonatomic, copy) NSString *password;
@property (nonatomic, assign) NSInteger age;
@end
// Person.m
#import "Person.h"
static NSString *const kAge = @"age";
static NSString *const kName = @"name";
static NSString *const kEmail = @"email";
static NSString *const kPassword = @"password";
@implementation Person
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeInteger:self.age forKey:kAge];
[coder encodeObject:self.name forKey:kName];
[coder encodeObject:self.email forKey:kEmail];
[coder encodeObject:self.password forKey:kPassword];
}
- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
if (self) {
_age = [coder decodeIntegerForKey:kAge];
_name = [[coder decodeObjectForKey:kName] copy];
_email = [[coder decodeObjectForKey:kEmail] copy];
_password = [[coder decodeObjectForKey:kPassword] copy];
}
return self;
}
- (void)dealloc {
[_name release];
[_email release];
[_password release];
[super dealloc];
}
@end
#import
#import "Person.h"
int main() {
@autoreleasepool {
// 建立物件
Person *person = [[Person alloc] init];
person.name = @"jack";
person.age = 20;
person.email = @"jack@163.com";
person.password = @"12345";
// 歸檔路徑
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/person.archive"];
// 歸檔
BOOL success = [NSKeyedArchiver archiveRootObject:person toFile:path];
if (success) NSLog(@"歸檔成功");
// 解檔
Person *restored = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"name=%@, age=%ld, email=%@, password=%@",
restored.name, restored.age, restored.email, restored.password);
}
return 0;
}
| 主題 | 說明 |
|---|---|
| 編碼基本型別 | `encodeInteger:forKey:` `encodeFloat:forKey:` `encodeBool:forKey:` 等 |
| 編碼物件 | `encodeObject:forKey:` (需物件也實現 NSCoding) |
| 解碼基本型別 | `decodeIntegerForKey:` `decodeFloatForKey:` `decodeBoolForKey:` |
| 解碼物件 | `decodeObjectForKey:` 回傳 `id`,需轉型並 `copy` (若屬性為 copy) |
| 版本演進 | 新增欄位時解碼端用 `decodeObjectForKey:` 可能回傳 `nil`,需提供預設值 |
| 安全性 | `NSKeyedArchiver` 預設不加密,敏感資料 (密碼) 應先加密再歸檔 |
| 替代方案 | JSON (Codable)、Protocol Buffers、Property List (plist) 適用跨平台/人類可讀場景 |
@interface Person : NSObject
+ (BOOL)supportsSecureCoding { return YES; }
// initWithCoder 中驗證類別
- (id)initWithCoder:(NSCoder*)coder {
self = [super init];
if (self) {
// 只解碼預期類別,防止物件注入攻擊
_name = [coder decodeObjectOfClass:[NSString class] forKey:kName];
...
}
return self;
}
`NSSecureCoding` 強制解碼時指定類別,提升安全性,App Store 上架建議採用。