Foundation 框架提供的集合類是 iOS/macOS 開發中數據組織的基石。本文系統梳理不可變/可變字典、集合(Set)家族、快速枚舉語法糖、數組排序多態機制,並附帶內存管理、性能特徵、常見陷阱與最佳實踐。
NSDictionary// 現代語法(推薦):字面量語法
NSDictionary *dict = @{
@"name": @"Guozai",
@"sex": @"Male",
@"age": @14
};
// 經典工廠方法
NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:
@"Guozai", @"name",
@"Male", @"sex",
@14, @"age",
nil];
// 核心操作
NSString *name = dict[@"name"]; // 下標訪問(現代語法)
NSString *age = [dict objectForKey:@"age"]; // 傳統方法
NSArray *allKeys = [dict allKeys]; // 所有鍵(無序)
NSArray *allValues = [dict allValues]; // 所有值
NSUInteger count = dict.count; // 鍵值對數量
// 遍歷
for (NSString *key in dict) { // 快速枚舉遍歷鍵
NSLog(@"%@: %@", key, dict[key]);
}
NSMutableDictionaryNSMutableDictionary *mDict = [NSMutableDictionary dictionaryWithDictionary:dict]; // 或 [NSMutableDictionary dictionary] 創建空字典 // 增/改:同一方法 [mDict setObject:@"100" forKey:@"score"]; // 添加或更新 mDict[@"nickname"] = @"GZ"; // 現代語法 // 刪 [mDict removeObjectForKey:@"sex"]; // 刪除指定鍵 [mDict removeAllObjects]; // 清空 // 查 NSString *val = mDict[@"age"]; // 同不可變
isEqual: 判斷,重複鍵後設值覆蓋前值。NSCopying:字典內部複製鍵(copy),故鍵類型必須實現 copyWithZone:(系統類型已實現,自定義類需遵循協議)。NSSetNSSet *set = @[@"Guozai", @"Zaiguo", @"Guoguo"]; // 現代語法 // 或 [NSSet setWithObjects:@[@"A", @"B", @"C"] count:3]; // 核心操作 NSArray *all = [set allObjects]; // 轉數組遍歷 NSUInteger cnt = set.count; BOOL has = [set containsObject:@"Guozai"]; // O(1) 平均查找 id any = [set anyObject]; // 任意元素(通常首個)
NSMutableSetNSMutableSet *mSet = [NSMutableSet setWithSet:set]; [mSet addObject:@"Zaizai"]; // 添加 [mSet removeObject:@"Zaizai"]; // 刪除 [mSet unionSet:otherSet]; // 並集(就地修改) [mSet intersectSet:otherSet]; // 交集 [mSet minusSet:otherSet]; // 差集
NSCountedSet(NSMutableSet 子類)NSCountedSet *cSet = [NSCountedSet setWithSet:mSet]; [cSet addObject:@"Guozai"]; // 重複添加 NSUInteger cnt = [cSet countForObject:@"Guozai"]; // 返回 2 // 內部維護元素->計數映射,適用於詞頻統計等場景
| 特性 | NSArray | NSDictionary | NSSet |
|---|---|---|---|
| 有序性 | 有序(索引) | 無序 | 無序 |
| 查找複雜度 | O(n) | O(1) 平均 | O(1) 平均 |
| 元素唯一性 | 可重複 | 鍵唯一,值可重複 | 元素唯一 |
| 典型場景 | 列表、隊列、棧 | 鍵值映射、JSON 解析 | 去重、成員資格測試、集合運算 |
// 所有集合類遵循 NSFastEnumeration 協議
// 編譯器將 for-in 轉換為基於 countByEnumeratingWithState:objects:count: 的迭代器調用
// 數組枚舉
NSMutableArray *arr = [@[@"1", @"2", @"3"] mutableCopy];
for (NSString *str in arr) {
NSLog(@"%@", str);
// [arr addObject:@"4"]; // 崩潰!枚舉期間修改集合 → 異常
}
// 字典枚舉:遍歷鍵
NSMutableDictionary *mDict = [@{@"name":@"Guozai", @"sex":@"Male"} mutableCopy];
for (NSString *key in mDict) { // 遍歷的是 Key!
NSLog(@"Key: %@, Value: %@", key, mDict[key]);
}
// 集合枚舉
NSMutableSet *mSet = [@[@"1", @"2"] mutableCopy];
for (NSString *str in mSet) {
NSLog(@"%@", str);
}
鐵律:快速枚舉期間嚴禁修改集合內容(增/刪/改),否則拋出 NSGenericException。需先收集待操作項,枚舉結束後批量處理。
// 返回新數組(不修改原數組)
NSArray *sorted = [array sortedArrayUsingSelector:@selector(compare:)]; // 元素需實現 compare:
NSArray *sorted2 = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2]; // Block 方式,更靈活
}];
NSArray *sorted3 = [array sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"price" ascending:YES]]]; // KVC 排序
// 就地排序(修改原數組,需 NSMutableArray)
[mutableArray sortUsingSelector:@selector(compare:)];
[mutableArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { ... }];
[mutableArray sortUsingDescriptors:@[...]];
// Student.h
@interface Student : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) CGFloat price;
- (NSComparisonResult)compareByPrice:(Student *)other;
@end
// Student.m
- (NSComparisonResult)compareByPrice:(Student *)other {
if (self.price < other.price) return NSOrderedAscending; // -1: self 排前
if (self.price > other.price) return NSOrderedDescending; // 1: self 排後
return NSOrderedSame; // 0: 相等
}
// 使用
NSArray *students = @[stu1, stu2, stu3];
NSArray *sorted = [students sortedArrayUsingSelector:@selector(compareByPrice:)];
// 升序:price 低 → 高
NSComparisonResult 取值含義NSOrderedAscending (-1):左操作數 < 右操作數 → 左排前(升序)。NSOrderedSame (0):相等。NSOrderedDescending (1):左操作數 > 右操作數 → 左排後(升序)。description 重寫實現友好調試輸出- (NSString *)description {
return [NSString stringWithFormat:@"Student: name=%@, price=%.2f", _name, _price];
}
// 現在 NSLog(@"%@", student) 將輸出自定義格式,而非默認
@[], @{})創建不可變集合,語法簡潔且編譯器優化。NSString, NSNumber 等;避免用可變對象作鍵(修改後哈希值變導致查找失效)。NSSet:[NSSet setWithArray:largeArray] 即時去重,再 [set allObjects] 取回數組。sortedArrayUsingComparator: 支持多鍵排序、自定義邏輯,無需在模型中添加比較方法污染接口。總結:OC 集合類設計體現了類簇模式——對外暴露抽象接口(
NSArray),內部根據數據特徵動態選擇具體實現(__NSArrayI,__NSArrayM,__NSSingleObjectArrayI等)。理解不可變/可變雙重體系、快速枚舉協議、多態排序策略,能寫出高性能、可維護、符合 Cocoa 習慣的代碼。