Objective-C数组与集合类操作指南
Objective-C数组与集合类操作指南
一、NSArray 基础
- 定义与初始化
在Objective - C中,
NSArray
是不可变数组,一旦创建,其内容和长度就不能改变。定义和初始化NSArray
有多种方式。
最简单的方式是使用数组字面量:
NSArray *array1 = @[@"Apple", @"Banana", @"Cherry"];
这里使用@[]
语法创建了一个包含三个字符串对象的数组。
也可以通过NSArray
的类方法arrayWithObjects:
来创建数组:
NSString *str1 = @"Apple";
NSString *str2 = @"Banana";
NSString *str3 = @"Cherry";
NSArray *array2 = [NSArray arrayWithObjects:str1, str2, str3, nil];
注意,使用arrayWithObjects:
方法时,必须以nil
作为参数列表的结束标志,否则会导致未定义行为。
还可以通过从另一个数组创建新数组的方式:
NSArray *originalArray = @[@"One", @"Two", @"Three"];
NSArray *newArray = [NSArray arrayWithArray:originalArray];
- 访问元素
NSArray
的元素可以通过索引来访问,索引从0开始。例如:
NSArray *fruits = @[@"Apple", @"Banana", @"Cherry"];
NSString *firstFruit = fruits[0];
NSString *secondFruit = [fruits objectAtIndex:1];
这里通过数组字面量的[]
语法和objectAtIndex:
方法都能访问到数组中的元素。
- 数组的属性与方法
NSArray
有一些有用的属性和方法。比如count
属性可以获取数组中元素的个数:
NSArray *numbers = @[@1, @2, @3, @4];
NSUInteger count = numbers.count;
NSLog(@"数组元素个数: %lu", (unsigned long)count);
lastObject
方法可以获取数组的最后一个元素:
NSArray *words = @[@"Hello", @"World"];
id lastWord = [words lastObject];
NSLog(@"最后一个单词: %@", lastWord);
containsObject:
方法用于检查数组是否包含某个特定的对象:
NSArray *colors = @[@"Red", @"Green", @"Blue"];
BOOL containsGreen = [colors containsObject:@"Green"];
if (containsGreen) {
NSLog(@"数组包含绿色");
}
二、NSMutableArray
- 定义与初始化
NSMutableArray
是可变数组,允许在创建后添加、删除和修改元素。初始化NSMutableArray
可以使用以下方法:
NSMutableArray *mutableArray1 = [NSMutableArray array];
这创建了一个空的可变数组。也可以基于现有数组创建可变数组:
NSArray *original = @[@"A", @"B", @"C"];
NSMutableArray *mutableArray2 = [NSMutableArray arrayWithArray:original];
- 添加元素
addObject:
方法用于向数组末尾添加一个对象:
NSMutableArray *animals = [NSMutableArray array];
[animals addObject:@"Dog"];
[animals addObject:@"Cat"];
insertObject:atIndex:
方法可以在指定索引位置插入对象:
[animals insertObject:@"Rabbit" atIndex:1];
- 删除元素
removeObject:
方法用于删除数组中指定的对象:
[animals removeObject:@"Cat"];
removeObjectAtIndex:
方法则删除指定索引位置的对象:
[animals removeObjectAtIndex:0];
removeAllObjects
方法可以清空数组中的所有元素:
[animals removeAllObjects];
- 修改元素 通过索引可以直接修改可变数组中的元素:
NSMutableArray *numbers = [NSMutableArray arrayWithArray:@[@1, @2, @3]];
numbers[1] = @4;
也可以使用replaceObjectAtIndex:withObject:
方法:
[numbers replaceObjectAtIndex:2 withObject:@5];
三、NSDictionary 基础
- 定义与初始化
NSDictionary
是不可变字典,它存储键值对。定义和初始化NSDictionary
可以使用以下方式:
NSDictionary *dictionary1 = @{@"name": @"John", @"age": @30};
使用字典字面量,@""
作为键,对应的值可以是任何对象。
也可以通过dictionaryWithObjectsAndKeys:
方法创建字典:
NSString *name = @"Jane";
NSNumber *age = @25;
NSDictionary *dictionary2 = [NSDictionary dictionaryWithObjectsAndKeys:name, @"name", age, @"age", nil];
同样,以nil
作为参数列表的结束标志。
- 访问值 通过键可以访问字典中的值:
NSDictionary *person = @{@"name": @"Bob", @"city": @"New York"};
NSString *nameFromDict = person[@"name"];
NSString *city = [person objectForKey:@"city"];
这里通过字典字面量的[]
语法和objectForKey:
方法都能获取到对应键的值。
- 字典的属性与方法
count
属性可以获取字典中键值对的数量:
NSDictionary *book = @{@"title": @"Objective - C Programming", @"author": @"Unknown"};
NSUInteger pairCount = book.count;
NSLog(@"字典键值对数量: %lu", (unsigned long)pairCount);
allKeys
方法返回字典中所有键的数组,allValues
方法返回所有值的数组:
NSArray *keys = [book allKeys];
NSArray *values = [book allValues];
NSLog(@"所有键: %@", keys);
NSLog(@"所有值: %@", values);
四、NSMutableDictionary
- 定义与初始化
NSMutableDictionary
是可变字典,允许动态添加、删除和修改键值对。初始化方式如下:
NSMutableDictionary *mutableDict1 = [NSMutableDictionary dictionary];
创建一个空的可变字典。也可以基于现有字典创建:
NSDictionary *originalDict = @{@"a": @1, @"b": @2};
NSMutableDictionary *mutableDict2 = [NSMutableDictionary dictionaryWithDictionary:originalDict];
- 添加与修改键值对
使用
setObject:forKey:
方法可以添加或修改键值对:
NSMutableDictionary *student = [NSMutableDictionary dictionary];
[student setObject:@"Tom" forKey:@"name"];
[student setObject:@20 forKey:@"age"];
// 修改值
[student setObject:@"Jerry" forKey:@"name"];
- 删除键值对
removeObjectForKey:
方法用于删除指定键的键值对:
[student removeObjectForKey:@"age"];
removeAllObjects
方法可以清空字典中的所有键值对:
[student removeAllObjects];
五、NSSet 基础
- 定义与初始化
NSSet
是不可变集合,它存储无序的唯一对象。定义和初始化NSSet
可以使用以下方式:
NSSet *set1 = [NSSet setWithObjects:@"Apple", @"Banana", @"Cherry", nil];
使用setWithObjects:
方法,同样以nil
结束参数列表。
也可以使用集合字面量:
NSSet *set2 = @[@"Red", @"Green", @"Blue"];
- 集合操作
containsObject:
方法用于检查集合是否包含某个对象:
NSSet *colorsSet = @[@"Red", @"Green", @"Blue"];
BOOL containsRed = [colorsSet containsObject:@"Red"];
if (containsRed) {
NSLog(@"集合包含红色");
}
intersectsSet:
方法用于判断两个集合是否有交集:
NSSet *setA = @[@1, @2, @3];
NSSet *setB = @[@3, @4, @5];
BOOL hasIntersection = [setA intersectsSet:setB];
if (hasIntersection) {
NSLog(@"两个集合有交集");
}
isEqualToSet:
方法用于判断两个集合是否相等:
NSSet *setC = @[@"A", @"B", @"C"];
NSSet *setD = @[@"C", @"A", @"B"];
BOOL areEqual = [setC isEqualToSet:setD];
if (areEqual) {
NSLog(@"两个集合相等");
}
六、NSMutableSet
- 定义与初始化
NSMutableSet
是可变集合,允许动态添加和删除对象。初始化方式如下:
NSMutableSet *mutableSet1 = [NSMutableSet set];
创建一个空的可变集合。也可以基于现有集合创建:
NSSet *originalSet = @[@"One", @"Two", @"Three"];
NSMutableSet *mutableSet2 = [NSMutableSet setWithSet:originalSet];
- 添加与删除对象
addObject:
方法用于向集合中添加对象:
NSMutableSet *fruitSet = [NSMutableSet set];
[fruitSet addObject:@"Apple"];
[fruitSet addObject:@"Banana"];
removeObject:
方法用于删除集合中的对象:
[fruitSet removeObject:@"Banana"];
removeAllObjects
方法可以清空集合中的所有对象:
[fruitSet removeAllObjects];
七、集合类的内存管理
- 对象所有权
在Objective - C中,集合类(
NSArray
、NSMutableArray
、NSDictionary
、NSMutableDictionary
、NSSet
、NSMutableSet
)对其包含的对象拥有强引用。这意味着当对象被添加到集合中时,集合会保留该对象,对象的引用计数会增加。当对象从集合中移除或集合被销毁时,集合会释放对对象的引用,对象的引用计数会减少。
例如:
NSMutableArray *array = [NSMutableArray array];
NSString *str = [[NSString alloc] initWithString:@"Hello"];
[array addObject:str];
// str的引用计数增加
[str release];
// 此时str不会被释放,因为array持有它
[array removeObject:str];
// str的引用计数减少
// 如果这是str的最后一个强引用,str会被释放
- 自动释放池 在使用集合类时,要注意自动释放池的作用。当向集合中添加自动释放的对象时,这些对象会在最近的自动释放池被排空时释放。例如:
@autoreleasepool {
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 1000; i++) {
NSString *str = [NSString stringWithFormat:@"Object %d", i];
[array addObject:str];
// str是自动释放的对象
}
// 自动释放池排空时,str对象会被释放
}
合理使用自动释放池可以避免内存峰值,特别是在处理大量临时对象时。
八、集合类的遍历
- NSArray 和 NSMutableArray 的遍历
- 使用 for 循环:
NSArray *numbers = @[@1, @2, @3, @4];
for (NSUInteger i = 0; i < numbers.count; i++) {
NSNumber *number = numbers[i];
NSLog(@"数字: %@", number);
}
- 使用快速枚举:
NSArray *fruits = @[@"Apple", @"Banana", @"Cherry"];
for (NSString *fruit in fruits) {
NSLog(@"水果: %@", fruit);
}
- 使用 block 遍历:
NSArray *animals = @[@"Dog", @"Cat", @"Rabbit"];
[animals enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"动物 %lu: %@", (unsigned long)idx, obj);
if (idx == 1) {
*stop = YES;
}
}];
- NSDictionary 和 NSMutableDictionary 的遍历
- 遍历键值对:
NSDictionary *person = @{@"name": @"Alice", @"age": @28};
[person enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"键: %@, 值: %@", key, obj);
}];
- 遍历键:
NSDictionary *book = @{@"title": @"Programming in Objective - C", @"author": @"Author Name"};
for (NSString *key in book) {
NSLog(@"键: %@", key);
}
- NSSet 和 NSMutableSet 的遍历
- 使用快速枚举:
NSSet *colors = @[@"Red", @"Green", @"Blue"];
for (NSString *color in colors) {
NSLog(@"颜色: %@", color);
}
- 使用 block 遍历:
NSSet *numbersSet = @[@1, @2, @3];
[numbersSet enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
NSLog(@"数字: %@", obj);
if ([obj isEqualToNumber:@2]) {
*stop = YES;
}
}];
九、集合类的类型安全
- 泛型语法
从Xcode 7开始,Objective - C支持泛型语法,这可以提高集合类的类型安全性。例如,定义一个只包含
NSString
对象的数组:
NSArray<NSString *> *stringArray = @[@"Hello", @"World"];
这样,编译器会在编译时检查数组中是否只添加了NSString
类型的对象。对于字典,也可以指定键和值的类型:
NSDictionary<NSString *, NSNumber *> *dict = @{@"count": @10, @"value": @20};
- 类型检查与转换 在没有使用泛型语法时,需要手动进行类型检查和转换。例如,从数组中获取对象并转换为正确的类型:
NSArray *objects = @[@"One", @1];
for (id object in objects) {
if ([object isKindOfClass:[NSString class]]) {
NSString *str = (NSString *)object;
NSLog(@"字符串: %@", str);
} else if ([object isKindOfClass:[NSNumber class]]) {
NSNumber *num = (NSNumber *)object;
NSLog(@"数字: %@", num);
}
}
使用泛型可以减少这种手动类型检查和转换的工作量,同时提高代码的可读性和安全性。
十、集合类在实际项目中的应用
- 数据存储与管理
在iOS应用开发中,
NSArray
和NSDictionary
常被用于存储和管理数据。例如,从服务器获取的JSON数据通常会被解析为NSArray
或NSDictionary
。假设我们从服务器获取了一个包含用户信息的JSON数组,解析后可能得到如下的NSArray
:
NSArray *users = @[
@{@"name": @"User1", @"age": @25},
@{@"name": @"User2", @"age": @30}
];
我们可以遍历这个数组,获取每个用户的信息并进行相应的处理。
2. 缓存机制
NSMutableDictionary
可以用于实现简单的缓存机制。例如,在一个图片加载器中,可以将已经加载的图片缓存起来,避免重复加载:
NSMutableDictionary *imageCache = [NSMutableDictionary dictionary];
- (UIImage *)loadImageWithURL:(NSURL *)url {
UIImage *image = imageCache[url];
if (image) {
return image;
}
// 从URL加载图片
NSData *imageData = [NSData dataWithContentsOfURL:url];
image = [UIImage imageWithData:imageData];
imageCache[url] = image;
return image;
}
- 集合类与UI展示
在UI开发中,
NSArray
常与UITableView
或UICollectionView
结合使用。例如,我们有一个包含联系人姓名的NSArray
,可以将其作为数据源传递给UITableView
进行展示:
@interface ViewController () <UITableViewDataSource>
@property (nonatomic, strong) NSArray *contacts;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.contacts = @[@"Alice", @"Bob", @"Charlie"];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.dataSource = self;
[self.view addSubview:tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.contacts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
}
cell.textLabel.text = self.contacts[indexPath.row];
return cell;
}
@end
通过以上对Objective - C数组与集合类的详细介绍,包括基础操作、内存管理、遍历、类型安全以及实际应用等方面,开发者可以更好地掌握和运用这些数据结构,编写出高效、稳定且安全的Objective - C程序。无论是简单的iOS应用开发还是复杂的Mac OS应用,对集合类的熟练使用都是必不可少的技能。