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

Objective-C 字典完全指南:NSDictionary 與 NSMutableDictionary 實戰詳解

     編輯:關於C語言

核心類別體系

類別可變性繼承適用場景
NSDictionary不可變NSObject建立後不再修改,執行緒安全、效能最佳
NSMutableDictionary可變NSDictionary需動態增刪改查,單執行緒或加鎖使用

兩者皆為類別簇,實際實例為私有子類 (如 `__NSDictionaryI`, `__NSDictionaryM`)。

一、NSDictionary — 不可變字典

建立方式

// 1. 字面量語法 (現代、推薦)
NSDictionary *dict1 = @{ @"name": @"hechen", @"age": @25 };

// 2. 便利建構子
NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:
                       @"hechen", @"name",
                       @25, @"age",
                       nil];

// 3. 逐對建立
NSDictionary *dict3 = [NSDictionary dictionaryWithObject:@"hechen" forKey:@"name"];

// 4. 從陣列建立 (鍵值陣列長度必須相同)
NSArray *keys = @[@"name", @"age"];
NSArray *objs = @[@"hechen", @25];
NSDictionary *dict4 = [NSDictionary dictionaryWithObjects:objs forKeys:keys];

核心操作

NSUInteger count = [dict count];                    // 元素個數
id value = [dict objectForKey:@"name"];             // 取值 (無則回傳 nil)
NSArray *allKeys = [dict allKeys];                  // 所有鍵 (順序不定)
NSArray *allValues = [dict allValues];              // 所有值

// 快速枚舉 (推薦)
for (id key in dict) {
    NSLog(@"%@ -> %@", key, dict[key]);             // 下標語法等同 objectForKey:
}

// 過濾
NSPredicate *pred = [NSPredicate predicateWithFormat:@"key BEGINSWITH 'a'"];
NSDictionary *filtered = [dict filteredDictionaryUsingPredicate:pred];

序列化/持久化

// 寫入檔案 (Property List 格式,僅支援 Property List 型別)
[dict writeToFile:@"/tmp/config.plist" atomically:YES];

// JSON 序列化 (需值為 JSON 相容型別)
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
                                                   options:NSJSONWritingPrettyPrinted
                                                     error:nil];

二、NSMutableDictionary — 可變字典

建立與容量預留

// 預留初始容量,減少擴容次數
NSMutableDictionary *md = [NSMutableDictionary dictionaryWithCapacity:100];
// 實際容量會自動成長,無需擔心越界

增刪改查 (CRUD)

// 新增/修改 (鍵存在則覆蓋)
[md setObject:@"China" forKey:@"country"];
[md setObject:@100 forKey:@"score"];

// 批次新增
[md addEntriesFromDictionary:@{@"k1": @1, @"k2": @2}];

// 刪除單一鍵
[md removeObjectForKey:@"score"];

// 批次刪除
[md removeObjectsForKeys:@[@"k1", @"k2"]];

// 清空
[md removeAllObjects];

// 修改值 (Key-Value Coding)
[md setValue:@200 forKey:@"score"];  // 自動處理 nil -> 刪除鍵

安全遍歷與修改

// ❌ 錯誤:邊遍歷邊刪除會崩潰
// for (id key in md) { if ([key isEqualToString:@"bad"]) [md removeObjectForKey:key]; }

// ✅ 正確:先收集要刪除的鍵
NSMutableArray *keysToRemove = [NSMutableArray array];
for (id key in md) {
    if ([key hasPrefix:@"tmp_"]) [keysToRemove addObject:key];
}
[md removeObjectsForKeys:keysToRemove];

// ✅ 或使用 keysSortedByValueUsingSelector: 取得鍵陣列再操作

三、效能特徵與選擇指南

操作時間複雜度說明
查找 objectForKey:O(1) 平均雜湊表實作,良好雜湊函數下常數時間
插入/刪除O(1) 攤還負載因子超閾值觸發重新雜湊 (rehash)
枚舉O(n)遍歷所有桶位
記憶體開銷~2-3x 元素大小雜湊表需保持低負載因子 (通常 < 0.75)

選擇建議

  • 唯讀查找:`NSDictionary` (不可變、執行緒安全、記憶體較緊湊)
  • 頻繁修改:`NSMutableDictionary` (單執行緒或 `@synchronized` 保護)
  • 大量預知資料:用 `dictionaryWithCapacity:` 預留容量,避免多次 rehash
  • 鍵為整數/結構體:考慮 `NSMapTable` (弱引用鍵/值) 或 C++ `unordered_map` 透過橋接

四、進階主題

自訂鍵類別需實作

@interface MyKey : NSObject 
@property (copy) NSString *identifier;
@end

@implementation MyKey
- (BOOL)isEqual:(id)object {
    return [object isKindOfClass:[MyKey class]] &&
           [self.identifier isEqual:object.identifier];
}
- (NSUInteger)hash {
    return [self.identifier hash];
}
- (id)copyWithZone:(NSZone *)zone {
    return self; // 不可變物件可直接返回 self
}
@end

鐵律:作為字典鍵的物件必須實作 ``、`isEqual:`、`hash`,且不可變 (複製後語義不變)。

Key-Value Observing (KVO) 支援

NSMutableDictionary *md = [NSMutableDictionary dictionary];
[md addObserver:self forKeyPath:@"count" options:NSKeyValueObservingOptionNew context:nil];
// 修改 md 會觸發 observeValueForKeyPath:ofObject:change:context:

效能調優:預先計算雜湊

// 若鍵為大量字串,建立時預先計算 hash 可加速後續查找
// 但 NSString 已內建快取 hash,通常無需手動干預

五、常見陷阱速查

陷阱症狀修正
以可變物件作鍵修改鍵內容後查找失敗鍵必須不可變,或複製一份不可變副本
存入 nil 值編譯錯誤 / 執行期崩潰用 [NSNull null] 代表空值
多執行緒同時讀寫 NSMutableDictionary資料竄改、崩潰用 `@synchronized`、GCD serial queue、或改用不可變字典 + 原子交換
假設枚舉順序固定邏輯錯誤字典無序,勿依賴順序

六、Swift 互操作

// Swift 端
let nsDict: NSDictionary = ["name": "Swift", "version": 5]
let swiftDict = nsDict as? [String: Any] // 橋接為原生 Dictionary

// Objective-C 端
NSDictionary *dict = @{@"lang": @"ObjC"};
// Swift 可直接當作 [String: Any] 使用

結語

`NSDictionary`/`NSMutableDictionary` 是 Foundation 資料處理的基石。掌握建立方式、CRUD 操作、鍵的協定要求、執行緒安全、效能特徵,能避開 90% 的字典相關坑。原則:**預設用不可變字典,確有修改需求再升級為可變;鍵永遠用不可變物件。**

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