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

Objective-C 基礎集合類完全指南:字典、集合、快速枚舉與數組排序實戰

     編輯:關於C語言

OC 集合類核心:NSDictionary、NSSet、NSArray 及其可變體系深度解析

Foundation 框架提供的集合類是 iOS/macOS 開發中數據組織的基石。本文系統梳理不可變/可變字典、集合(Set)家族、快速枚舉語法糖、數組排序多態機制,並附帶內存管理、性能特徵、常見陷阱與最佳實踐。

一、 字典:鍵值對存儲的標準實現

1. 不可變字典 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]);
}

2. 可變字典 NSMutableDictionary

NSMutableDictionary *mDict = [NSMutableDictionary dictionaryWithDictionary:dict];
// 或 [NSMutableDictionary dictionary] 創建空字典

// 增/改:同一方法
[mDict setObject:@"100" forKey:@"score"]; // 添加或更新
mDict[@"nickname"] = @"GZ";               // 現代語法

// 刪
[mDict removeObjectForKey:@"sex"];        // 刪除指定鍵
[mDict removeAllObjects];                 // 清空

// 查
NSString *val = mDict[@"age"];            // 同不可變

3. 關鍵特性

  • 鍵唯一性:以 isEqual: 判斷,重複鍵後設值覆蓋前值。
  • 鍵需遵循 NSCopying:字典內部複製鍵(copy),故鍵類型必須實現 copyWithZone:(系統類型已實現,自定義類需遵循協議)。
  • 值不複製:僅保留強引用(ARC 下),值類型無複製要求。
  • 無序性:遍歷順序不保證與插入順序一致。

二、 集合:唯一元素的無序容器

1. 不可變集合 NSSet

NSSet *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];                  // 任意元素(通常首個)

2. 可變集合 NSMutableSet

NSMutableSet *mSet = [NSMutableSet setWithSet:set];
[mSet addObject:@"Zaizai"];      // 添加
[mSet removeObject:@"Zaizai"];   // 刪除
[mSet unionSet:otherSet];        // 並集(就地修改)
[mSet intersectSet:otherSet];    // 交集
[mSet minusSet:otherSet];        // 差集

3. 計數集合 NSCountedSet(NSMutableSet 子類)

NSCountedSet *cSet = [NSCountedSet setWithSet:mSet];
[cSet addObject:@"Guozai"];              // 重複添加
NSUInteger cnt = [cSet countForObject:@"Guozai"]; // 返回 2
// 內部維護元素->計數映射,適用於詞頻統計等場景

4. 集合 vs 字典 vs 數組選型

特性NSArrayNSDictionaryNSSet
有序性有序(索引)無序無序
查找複雜度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。需先收集待操作項,枚舉結束後批量處理。

四、 數組排序:多態比較器模式

1. 排序方法對比

// 返回新數組(不修改原數組)
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:@[...]];

2. 自定義模型比較器實現

// 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 低 → 高

3. NSComparisonResult 取值含義

  • NSOrderedAscending (-1):左操作數 < 右操作數 → 左排前(升序)。
  • NSOrderedSame (0):相等。
  • NSOrderedDescending (1):左操作數 > 右操作數 → 左排後(升序)。

五、 進階:description 重寫實現友好調試輸出

- (NSString *)description {
    return [NSString stringWithFormat:@"Student: name=%@, price=%.2f", _name, _price];
}
// 現在 NSLog(@"%@", student) 將輸出自定義格式,而非默認 

六、 最佳實踐總結

  1. 優先使用現代字面量語法(@[], @{})創建不可變集合,語法簡潔且編譯器優化。
  2. 按需選擇可變性:初始化後不再修改用不可變版本(線程安全、語義清晰、編譯器優化);需頻繁增刪用可變版本。
  3. 字典鍵用不可變對象:NSString, NSNumber 等;避免用可變對象作鍵(修改後哈希值變導致查找失效)。
  4. 大數據集去重用 NSSet:[NSSet setWithArray:largeArray] 即時去重,再 [set allObjects] 取回數組。
  5. 排序首選 Block/描述符:sortedArrayUsingComparator: 支持多鍵排序、自定義邏輯,無需在模型中添加比較方法污染接口。
  6. 快速枚舉只讀原則:嚴禁枚舉中修改集合,違者必崩。

總結:OC 集合類設計體現了類簇模式——對外暴露抽象接口(NSArray),內部根據數據特徵動態選擇具體實現(__NSArrayI, __NSArrayM, __NSSingleObjectArrayI 等)。理解不可變/可變雙重體系、快速枚舉協議、多態排序策略,能寫出高性能、可維護、符合 Cocoa 習慣的代碼。

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