首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Objective-C 資料持久化方案全解析:從歸檔到 Core Data

     編輯:關於C

前言:iOS/macOS 應用資料落地的四大路徑

在 Objective-C 開發中,資料持久化是核心需求。依據資料量、結構複雜度、查詢需求、安全性,主要有四大方案:

  1. NSKeyedArchiver 物件歸檔 — 適合小量、結構化物件圖
  2. 屬性列表 (NSArray/NSDictionary/NSUserDefaults) — 適合簡單設定、小量資料
  3. SQLite 資料庫 — 適合大量、關聯式、需高效查詢
  4. Core Data — 適合複雜物件圖、關聯管理、Undo/Redo、iCloud 同步

方案對比速查表

特性歸檔屬性列表SQLiteCore Data
資料量適用小 (<1MB)極小 (設定檔級)大 (GB 級)中大型
資料結構任意物件圖基本集合類型關聯表格管理物件模型
查詢能力無 (全讀全寫)無SQL 全功能NSPredicate 豐富
加密性二進位 (非明文)明文 (XML/二進位)可加密 (SQLCipher)可加密
效能序列化整體快 (小資料)極高 (索引)優化良好
適用場景文檔型、快照、快取用戶偏好、設定大量結構化資料複雜業務模型

一、NSKeyedArchiver 歸檔:最簡單的物件持久化

核心概念

  • 歸檔:將物件圖序列化為 NSData 寫入檔案
  • 解歸檔:從檔案讀取 NSData 還原物件圖
  • 協議:自訂類別必須實作 NSCoding (encodeWithCoder:、initWithCoder:)
  • Foundation 內建類別 (NSString、NSArray、NSDictionary、NSDate 等) 已實作 NSCoding

最簡單範例:陣列歸檔與解歸檔

@autoreleasepool {
    NSString *homeDir = NSHomeDirectory();
    NSArray *array = @[@"one", @"two", @"three"];
    NSString *filePath = [homeDir stringByAppendingPathComponent:@"Desktop/test.archive"];

    // 歸檔
    if (![NSKeyedArchiver archiveRootObject:array toFile:filePath]) {
        NSLog(@"歸檔失敗");
    } else {
        // 解歸檔
        NSArray *data = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
        NSLog(@"%@", data);  // 輸出: (one, two, three)
    }
    NSLog(@"Hello, World!");
}

進階:複雜物件歸檔 (NSKeyedArchiver + NSMutableData)

適用於需手動控制編碼流程、分批寫入、或加入中繼資料的場景:

NSString *homeDir = NSHomeDirectory();
NSString *filePath = [homeDir stringByAppendingPathComponent:@"Desktop/usertest.archive"];

NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

NSArray *nameArray = @[@"andy", @"yang"];
[archiver encodeInt:100 forKey:@"age"];
[archiver encodeObject:nameArray forKey:@"names"];
[archiver finishEncoding];
[archiver release];

// 寫入檔案
if ([data writeToFile:filePath atomically:YES]) {
    // 解歸檔
    NSData *data2 = [NSData dataWithContentsOfFile:filePath];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data2];
    int age = [unarchiver decodeIntForKey:@"age"];
    NSArray *array2 = [unarchiver decodeObjectForKey:@"names"];
    NSLog(@"%d", age);      // 100
    NSLog(@"%@", array2);   // (andy, yang)
    [unarchiver release];
} else {
    NSLog(@"write to file wrong");
}

自訂類別實作 NSCoding 範例

// Person.h
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end

// Person.m
@implementation Person
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeInteger:self.age forKey:@"age"];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        _name = [coder decodeObjectForKey:@"name"];
        _age = [coder decodeIntegerForKey:@"age"];
    }
    return self;
}
@end

二、屬性列表:輕量級設定儲存

NSUserDefaults — 最常用的 Key-Value 儲存

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 寫入
[defaults setObject:@"dark" forKey:@"theme"];
[defaults setBool:YES forKey:@"notificationsEnabled"];
[defaults synchronize];  // 同步到磁碟 (iOS 8+ 可省略)

// 讀取
NSString *theme = [defaults stringForKey:@"theme"];
BOOL enabled = [defaults boolForKey:@"notificationsEnabled"];
  • 適合:用戶偏好、啟動參數、小型狀態
  • 不適合:大量資料、複雜結構、敏感資訊 (未加密)

NSArray/NSDictionary writeToFile — 直接存取 plist 檔

NSDictionary *config = @{
    @"server": @"api.example.com",
    @"port": @(443),
    @"enabled": @YES
};
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject 
                  stringByAppendingPathComponent:@"config.plist"];
[config writeToFile:path atomically:YES];  // 自動產生 XML plist

三、SQLite:輕量級關聯資料庫

  • C 語言 API,需手動管理連線、Statement、Binding
  • 推薦使用 FMDB (OC 包裝) 或 GRDB.swift (Swift) 簡化操作
  • 支援索引、事務、WAL 模式、加密擴展 (SQLCipher)

四、Core Data:物件圖管理框架 (非單純資料庫)

核心優勢

  • 管理物件生命週期、關聯、反向關聯
  • 支援 NSFetchedResultsController 高效驅動 TableView
  • 內建 Undo/Redo、遷移、iCloud 同步
  • 底層可用 SQLite、XML、Binary、In-Memory 儲存

最小啟動堆疊 (NSPersistentContainer, iOS 10+)

// AppDelegate.m
@property (readonly, strong) NSPersistentContainer *persistentContainer;

- (NSPersistentContainer *)persistentContainer {
    if (!_persistentContainer) {
        _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"MyModel"];
        [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *desc, NSError *error) {
            if (error) NSLog(@"Core Data load error: %@", error);
        }];
    }
    return _persistentContainer;
}

// 使用範例
NSManagedObjectContext *ctx = self.persistentContainer.viewContext;
Person *p = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:ctx];
p.name = @"John";
p.age = @30;
[ctx save:nil];

選型決策樹

  1. 資料 < 100KB、單純 Key-Value → NSUserDefaults
  2. 資料 < 1MB、樹狀結構、不需查詢 → NSKeyedArchiver / plist
  3. 資料 > 1MB、需篩選/排序/關聯、多執行緒 → SQLite (FMDB) 或 Core Data
  4. 複雜物件圖、Undo/Redo、iCloud、TableView 驅動 → Core Data
  5. 跨平台、既有 SQL 技能、極致效能 → SQLite

安全性補充

  • 敏感資料 (Token、密碼) → Keychain (非上述四種)
  • 檔案層級加密 → NSFileProtectionComplete、DataProtection entitlement
  • SQLite 加密 → SQLCipher (開源、透明加密)

總結

沒有銀彈,只有適合場景的選擇。理解各方案的資料模型、查詢能力、效能特性、安全性,才能在架構初期做對決策,避免後期痛苦遷移。建議:小專案從 NSUserDefaults + 歸檔起步,業務增長再引入 Core Data 或 SQLite。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved