Objective-C 集合框架(NSArray、NSDictionary 等)详解
Objective-C 集合框架概述
在 Objective-C 编程中,集合框架提供了强大的数据存储和管理功能。集合框架主要包括 NSArray、NSMutableArray、NSDictionary、NSMutableDictionary 以及 NSSet、NSMutableSet 等类。这些类让开发者能够高效地处理一组数据,无论是简单的有序列表,还是复杂的键值对集合。
NSArray
1. 不可变数组的定义与初始化
NSArray 是一个不可变数组类,一旦创建,其内容就不能被修改。定义和初始化 NSArray 有多种方式。
- 使用 @[] 字面量语法
这种方式简洁明了,是现代 Objective-C 中常用的初始化数组的方法。NSArray *array1 = @[@"Apple", @"Banana", @"Cherry"];
- 使用 arrayWithObjects: 方法
注意,使用NSArray *array2 = [NSArray arrayWithObjects:@"Dog", @"Cat", @"Bird", nil];
arrayWithObjects:
方法时,必须以nil
作为参数列表的结束标志。
2. 访问数组元素
NSArray 的元素可以通过索引进行访问,索引从 0 开始。
NSArray *fruits = @[@"Apple", @"Banana", @"Cherry"];
NSString *firstFruit = fruits[0];
NSString *secondFruit = [fruits objectAtIndex:1];
这里,fruits[0]
和 [fruits objectAtIndex:0]
两种方式都可以获取数组的第一个元素。
3. 数组的属性与方法
- count 属性:用于获取数组中元素的个数。
NSArray *numbers = @[@1, @2, @3, @4, @5]; NSUInteger count = numbers.count; NSLog(@"数组元素个数: %lu", (unsigned long)count);
- containsObject: 方法:判断数组是否包含某个特定的对象。
NSArray *colors = @[@"Red", @"Green", @"Blue"]; BOOL containsGreen = [colors containsObject:@"Green"]; if (containsGreen) { NSLog(@"数组包含 Green"); } else { NSLog(@"数组不包含 Green"); }
- indexOfObject: 方法:获取某个对象在数组中的索引,如果对象不存在则返回 NSNotFound。
NSArray *animals = @[@"Lion", @"Tiger", @"Bear"]; NSUInteger index = [animals indexOfObject:@"Tiger"]; if (index != NSNotFound) { NSLog(@"Tiger 的索引是: %lu", (unsigned long)index); } else { NSLog(@"Tiger 不在数组中"); }
NSMutableArray
1. 可变数组的定义与初始化
NSMutableArray 继承自 NSArray,它允许在创建后添加、删除和修改数组中的元素。
- 使用 @[] 字面量语法结合 mutableCopy 方法
NSArray *immutableArray = @[@"One", @"Two", @"Three"]; NSMutableArray *mutableArray1 = [immutableArray mutableCopy];
- 直接使用 NSMutableArray 的初始化方法
NSMutableArray *mutableArray2 = [NSMutableArray arrayWithObjects:@"Four", @"Five", nil];
2. 添加元素
- addObject: 方法:向数组末尾添加一个对象。
NSMutableArray *shoppingList = [NSMutableArray arrayWithObject:@"Milk"]; [shoppingList addObject:@"Bread"];
- insertObject:atIndex: 方法:在指定索引位置插入一个对象。
NSMutableArray *numbers = [NSMutableArray arrayWithArray:@[@1, @3, @4]]; [numbers insertObject:@2 atIndex:1];
3. 删除元素
- removeObject: 方法:从数组中删除指定的对象。
NSMutableArray *colors = [NSMutableArray arrayWithArray:@[@"Red", @"Green", @"Blue"]]; [colors removeObject:@"Green"];
- removeObjectAtIndex: 方法:删除指定索引位置的对象。
NSMutableArray *fruits = [NSMutableArray arrayWithArray:@[@"Apple", @"Banana", @"Cherry"]]; [fruits removeObjectAtIndex:1];
- removeAllObjects 方法:清空数组中的所有元素。
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@"A", @"B", @"C"]]; [array removeAllObjects];
4. 修改元素
可以直接通过索引来修改可变数组中的元素。
NSMutableArray *words = [NSMutableArray arrayWithArray:@[@"Hello", @"World"]];
words[1] = @"Universe";
NSDictionary
1. 不可变字典的定义与初始化
NSDictionary 是一个不可变的键值对集合,每个键必须是唯一的。
- 使用 @{} 字面量语法
NSDictionary *person = @{@"name": @"John", @"age": @30, @"city": @"New York"};
- 使用 dictionaryWithObjectsAndKeys: 方法
同样,NSDictionary *book = [NSDictionary dictionaryWithObjectsAndKeys:@"Objective-C Programming", @"title", @"Author Name", @"author", nil];
dictionaryWithObjectsAndKeys:
方法需要以nil
结束参数列表,并且对象在前,键在后。
2. 访问字典值
可以通过键来访问字典中的值。
NSDictionary *car = @{@"brand": @"Toyota", @"model": @"Corolla", @"year": @2023};
NSString *brand = car[@"brand"];
NSNumber *year = [car objectForKey:@"year"];
这里,car[@"brand"]
和 [car objectForKey:@"brand"]
两种方式都能获取对应键的值。
3. 字典的属性与方法
- count 属性:获取字典中键值对的数量。
NSDictionary *countries = @{@"USA": @"Washington, D.C.", @"China": @"Beijing", @"France": @"Paris"}; NSUInteger count = countries.count; NSLog(@"字典中键值对数量: %lu", (unsigned long)count);
- allKeys 方法:获取字典中所有的键。
NSDictionary *languages = @{@"en": @"English", @"zh": @"Chinese", @"fr": @"French"}; NSArray *keys = languages.allKeys; NSLog(@"所有键: %@", keys);
- allValues 方法:获取字典中所有的值。
NSArray *values = languages.allValues; NSLog(@"所有值: %@", values);
NSMutableDictionary
1. 可变字典的定义与初始化
NSMutableDictionary 继承自 NSDictionary,允许在创建后添加、删除和修改键值对。
- 使用 @{} 字面量语法结合 mutableCopy 方法
NSDictionary *immutableDict = @{@"key1": @"value1", @"key2": @"value2"}; NSMutableDictionary *mutableDict1 = [immutableDict mutableCopy];
- 直接使用 NSMutableDictionary 的初始化方法
NSMutableDictionary *mutableDict2 = [NSMutableDictionary dictionaryWithObject:@"Initial Value" forKey:@"Initial Key"];
2. 添加键值对
- setObject:forKey: 方法:添加一个新的键值对,如果键已存在,则更新对应的值。
NSMutableDictionary *settings = [NSMutableDictionary dictionary]; [settings setObject:@"Dark Mode" forKey:@"theme"];
3. 删除键值对
- removeObjectForKey: 方法:删除指定键对应的键值对。
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:@{@"name": @"Alice", @"email": @"alice@example.com"}]; [userInfo removeObjectForKey:@"email"];
- removeAllObjects 方法:清空字典中的所有键值对。
NSMutableDictionary *data = [NSMutableDictionary dictionaryWithDictionary:@{@"a": @1, @"b": @2, @"c": @3}]; [data removeAllObjects];
4. 修改键值对
可以直接通过键来修改可变字典中的值。
NSMutableDictionary *config = [NSMutableDictionary dictionaryWithDictionary:@{@"server": @"localhost", @"port": @8080}];
config[@"port"] = @8081;
NSSet
1. 不可变集合的定义与初始化
NSSet 是一个不可变的无序集合,集合中的元素是唯一的。
- 使用 @{} 字面量语法
NSSet *set1 = @[@"Apple", @"Banana", @"Cherry"];
- 使用 setWithObjects: 方法
NSSet *set2 = [NSSet setWithObjects:@"Dog", @"Cat", @"Bird", nil];
2. 集合的属性与方法
- count 属性:获取集合中元素的个数。
NSSet *numbers = [NSSet setWithObjects:@1, @2, @3, nil]; NSUInteger count = numbers.count; NSLog(@"集合元素个数: %lu", (unsigned long)count);
- containsObject: 方法:判断集合是否包含某个特定的对象。
NSSet *colors = [NSSet setWithObjects:@"Red", @"Green", @"Blue", nil]; BOOL containsGreen = [colors containsObject:@"Green"]; if (containsGreen) { NSLog(@"集合包含 Green"); } else { NSLog(@"集合不包含 Green"); }
NSMutableSet
1. 可变集合的定义与初始化
NSMutableSet 继承自 NSSet,允许在创建后添加和删除元素。
- 使用 set 初始化方法
NSMutableSet *mutableSet = [NSMutableSet set];
- 使用 setWithSet: 方法从现有集合初始化
NSSet *immutableSet = [NSSet setWithObjects:@"One", @"Two", nil]; NSMutableSet *mutableSet2 = [NSMutableSet setWithSet:immutableSet];
2. 添加元素
- addObject: 方法:向集合中添加一个对象,如果对象已存在,则不会重复添加。
NSMutableSet *shoppingSet = [NSMutableSet setWithObject:@"Milk"]; [shoppingSet addObject:@"Bread"];
3. 删除元素
- removeObject: 方法:从集合中删除指定的对象。
NSMutableSet *fruitSet = [NSMutableSet setWithObjects:@"Apple", @"Banana", @"Cherry", nil]; [fruitSet removeObject:@"Banana"];
集合框架的内存管理
在 Objective-C 中,集合框架中的对象通常遵循引用计数的内存管理机制。当一个对象被添加到集合中时,集合会对该对象进行一次 retain(在 ARC 环境下,相当于增加引用计数)。当对象从集合中移除或者集合本身被释放时,集合会对对象进行一次 release(在 ARC 环境下,相当于减少引用计数)。
例如,在手动引用计数(MRC)环境下:
NSString *string = [[NSString alloc] initWithString:@"Example"];
NSMutableArray *array = [NSMutableArray array];
[array addObject:string];
[string release]; // 此时 string 的引用计数为 1,因为 array 持有它
[array removeObjectAtIndex:0]; // 此时 string 的引用计数变为 0,会被释放
在自动引用计数(ARC)环境下,开发者无需手动管理对象的引用计数,编译器会自动处理。
集合框架的性能考量
不同的集合类型在性能上有各自的特点。
- NSArray:对于按顺序访问元素的场景,NSArray 表现出色,因为可以通过索引快速定位元素。查找特定元素时,如果元素数量较多,
indexOfObject:
方法的时间复杂度为 O(n),性能相对较低。 - NSDictionary:NSDictionary 适用于通过键快速查找值的场景,其查找操作的平均时间复杂度为 O(1)。但如果键的数量非常大,哈希冲突可能会影响性能。
- NSSet:NSSet 适合判断元素是否存在的场景,其
containsObject:
方法平均时间复杂度为 O(1)。由于集合是无序的,不适合需要顺序访问元素的场景。
集合框架的遍历
1. NSArray 的遍历
- 使用 for 循环
NSArray *fruits = @[@"Apple", @"Banana", @"Cherry"]; for (NSUInteger i = 0; i < fruits.count; i++) { NSString *fruit = fruits[i]; NSLog(@"%@", fruit); }
- 使用 fast enumeration
for (NSString *fruit in fruits) { NSLog(@"%@", fruit); }
- 使用 block 遍历
[fruits enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSLog(@"%@ at index %lu", obj, (unsigned long)idx); if (idx == 1) { *stop = YES; } }];
2. NSDictionary 的遍历
- 使用 fast enumeration 遍历键
NSDictionary *person = @{@"name": @"John", @"age": @30, @"city": @"New York"}; for (NSString *key in person) { id value = person[key]; NSLog(@"%@: %@", key, value); }
- 使用 block 遍历键值对
[person enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { NSLog(@"%@: %@", key, obj); }];
3. NSSet 的遍历
- 使用 fast enumeration
NSSet *colors = [NSSet setWithObjects:@"Red", @"Green", @"Blue", nil]; for (NSString *color in colors) { NSLog(@"%@", color); }
- 使用 block 遍历
[colors enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { NSLog(@"%@", obj); }];
集合框架与其他数据类型的转换
1. NSArray 与 C 数组的转换
- NSArray 转 C 数组
NSArray *numbers = @[@1, @2, @3]; NSUInteger count = numbers.count; int cArray[count]; [numbers getObjects:(id *)cArray range:NSMakeRange(0, count)]; for (NSUInteger i = 0; i < count; i++) { NSLog(@"%d", cArray[i]); }
- C 数组转 NSArray
int cArray2[] = {4, 5, 6}; NSArray *arrayFromC = [NSArray arrayWithObjects:[NSNumber numberWithInt:cArray2[0]], [NSNumber numberWithInt:cArray2[1]], [NSNumber numberWithInt:cArray2[2]], nil];
2. NSDictionary 与 JSON 的转换
- NSDictionary 转 JSON 数据
NSDictionary *data = @{@"name": @"Alice", @"age": @25}; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"%@", jsonString);
- JSON 数据转 NSDictionary
NSString *jsonString2 = @"{\"name\":\"Bob\",\"age\":30}"; NSData *jsonData2 = [jsonString2 dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *dictFromJSON = [NSJSONSerialization JSONObjectWithData:jsonData2 options:NSJSONReadingMutableContainers error:nil];
通过对 Objective-C 集合框架中 NSArray、NSDictionary、NSSet 及其可变版本的详细介绍,开发者可以根据具体的需求选择合适的集合类型,高效地处理数据。同时,对集合框架的内存管理、性能考量、遍历方式以及与其他数据类型的转换等方面的理解,有助于编写出更加健壮和高效的 Objective-C 程序。