Foundation 框架提供的集合類(NSArray/NSDictionary/NSSet 及其可變對應類)是 iOS/macOS 開發的基石。本文系統整理不可變/可變字典、集合(含計數集合)、快速枚舉、數組排序(含數值排序陷阱)的核心 API、典型用法與性能考量。
NSCopying 協議(通常用 NSString),Value 必須是對象。// 不可變字典 - 現代語法 @{key: value, ...}
NSDictionary *dict = @{
@"name": @"ZhangSan",
@"age": @18,
@"sex": @"Man"
};
// 讀取
NSString *name = dict[@"name"]; // 現代下標語法,等同 objectForKey:
NSArray *allKeys = [dict allKeys];
NSArray *allValues = [dict allValues];
// 快速枚舉 - 遍歷 Key
for (NSString *key in dict) {
NSLog(@"%@: %@", key, dict[key]);
}
// 可變字典
NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
mDict[@"height"] = @"170cm"; // 新增/修改
[mDict removeObjectForKey:@"age"]; // 刪除
// 批量操作
[mDict addEntriesFromDictionary:anotherDict];
// 創建
NSSet *set = [NSSet setWithObjects:@"北京", @"上海", @"廣州", nil];
// 注意:重複元素會被自動去重
// 判斷包含
if ([set containsObject:@"北京"]) { ... }
// 遍歷
for (NSString *city in set) { ... }
// 可變集合操作
NSMutableSet *mSet = [set mutableCopy];
[mSet addObject:@"深圳"];
[mSet removeObject:@"上海"];
[mSet unionSet:anotherSet]; // 並集
[mSet intersectSet:anotherSet]; // 交集
// NSCountedSet - 統計詞頻
NSArray *words = @[@"apple", @"banana", @"apple", @"apple", @"orange"];
NSCountedSet *counted = [NSCountedSet setWithArray:words];
NSLog(@"apple count: %lu", (unsigned long)[counted countForObject:@"apple"]); // 3
for (Type *obj in collection) { ... }
| 集合類型 | 枚舉產出 | 示例 |
|---|---|---|
| NSArray | 元素對象 | for (id obj in array) |
| NSDictionary | Key | for (id key in dict) -> dict[key] |
| NSSet | 元素對象 | for (id obj in set) |
快速枚舉比傳統 for (int i=0; i
適用於元素實現 compare: 方法的對象(NSString、NSNumber、NSDate 等)。
// 可變數組原地排序 NSMutableArray *mArr = [@[@3, @1, @4, @2] mutableCopy]; [mArr sortUsingSelector:@selector(compare:)]; // 結果: 1, 2, 3, 4 // 不可變數組返回新排序數組 NSArray *sorted = [@[@4, @2, @1, @3] sortedArrayUsingSelector:@selector(compare:)];
靈活控制升降序、多字段排序。
NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
// 降序
return [obj2 compare:obj1];
}];
錯誤示範:數組存放 NSString 形式的數字 @[@"10", @"2", @"1"] 直接用 compare: 會按字典序排序為 1, 10, 2。
正確做法:轉為 NSNumber 再排序,或使用 Block 比較 integerValue。
NSArray *stringNumbers = @[@"10", @"2", @"1", @"20"];
NSArray *correctSorted = [stringNumbers sortedArrayUsingComparator:^NSComparisonResult(NSString *s1, NSString *s2) {
return @([s1 integerValue]).compare(@([s2 integerValue]));
}];
// 結果: 1, 2, 10, 20
// 或預先轉換為 NSNumber 數組
NSArray *numbers = [stringNumbers valueForKeyPath:@"@integerValue.self"]; // KVC 技巧
NSArray *sortedNumbers = [numbers sortedArrayUsingSelector:@selector(compare:)];
| 場景 | 推薦類型 | 理由 |
|---|---|---|
| 頻繁按索引隨機訪問、順序遍歷 | NSArray | 連續內存,O(1) 索引,緩存友好 |
| 頻繁增刪、不關心順序、需去重 | NSSet / NSMutableSet | 哈希表 O(1) 查找/插入/刪除 |
| 鍵值映射、配置表、JSON 解析 | NSDictionary / NSMutableDictionary | 哈希表 O(1) 存取 |
| 需統計元素出現次數 | NSCountedSet | 內建計數器 |
@[]、@{}、@() 創建集合,代碼更簡潔安全。mutableCopy,利於線程安全與優化。compare:,字符串數字務必轉 NSNumber。