MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C数组与集合类操作指南

2023-11-052.9k 阅读

Objective-C数组与集合类操作指南

一、NSArray 基础

  1. 定义与初始化 在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];
  1. 访问元素 NSArray的元素可以通过索引来访问,索引从0开始。例如:
NSArray *fruits = @[@"Apple", @"Banana", @"Cherry"];
NSString *firstFruit = fruits[0];
NSString *secondFruit = [fruits objectAtIndex:1];

这里通过数组字面量的[]语法和objectAtIndex:方法都能访问到数组中的元素。

  1. 数组的属性与方法 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

  1. 定义与初始化 NSMutableArray是可变数组,允许在创建后添加、删除和修改元素。初始化NSMutableArray可以使用以下方法:
NSMutableArray *mutableArray1 = [NSMutableArray array];

这创建了一个空的可变数组。也可以基于现有数组创建可变数组:

NSArray *original = @[@"A", @"B", @"C"];
NSMutableArray *mutableArray2 = [NSMutableArray arrayWithArray:original];
  1. 添加元素 addObject:方法用于向数组末尾添加一个对象:
NSMutableArray *animals = [NSMutableArray array];
[animals addObject:@"Dog"];
[animals addObject:@"Cat"];

insertObject:atIndex:方法可以在指定索引位置插入对象:

[animals insertObject:@"Rabbit" atIndex:1];
  1. 删除元素 removeObject:方法用于删除数组中指定的对象:
[animals removeObject:@"Cat"];

removeObjectAtIndex:方法则删除指定索引位置的对象:

[animals removeObjectAtIndex:0];

removeAllObjects方法可以清空数组中的所有元素:

[animals removeAllObjects];
  1. 修改元素 通过索引可以直接修改可变数组中的元素:
NSMutableArray *numbers = [NSMutableArray arrayWithArray:@[@1, @2, @3]];
numbers[1] = @4;

也可以使用replaceObjectAtIndex:withObject:方法:

[numbers replaceObjectAtIndex:2 withObject:@5];

三、NSDictionary 基础

  1. 定义与初始化 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作为参数列表的结束标志。

  1. 访问值 通过键可以访问字典中的值:
NSDictionary *person = @{@"name": @"Bob", @"city": @"New York"};
NSString *nameFromDict = person[@"name"];
NSString *city = [person objectForKey:@"city"];

这里通过字典字面量的[]语法和objectForKey:方法都能获取到对应键的值。

  1. 字典的属性与方法 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

  1. 定义与初始化 NSMutableDictionary是可变字典,允许动态添加、删除和修改键值对。初始化方式如下:
NSMutableDictionary *mutableDict1 = [NSMutableDictionary dictionary];

创建一个空的可变字典。也可以基于现有字典创建:

NSDictionary *originalDict = @{@"a": @1, @"b": @2};
NSMutableDictionary *mutableDict2 = [NSMutableDictionary dictionaryWithDictionary:originalDict];
  1. 添加与修改键值对 使用setObject:forKey:方法可以添加或修改键值对:
NSMutableDictionary *student = [NSMutableDictionary dictionary];
[student setObject:@"Tom" forKey:@"name"];
[student setObject:@20 forKey:@"age"];
// 修改值
[student setObject:@"Jerry" forKey:@"name"];
  1. 删除键值对 removeObjectForKey:方法用于删除指定键的键值对:
[student removeObjectForKey:@"age"];

removeAllObjects方法可以清空字典中的所有键值对:

[student removeAllObjects];

五、NSSet 基础

  1. 定义与初始化 NSSet是不可变集合,它存储无序的唯一对象。定义和初始化NSSet可以使用以下方式:
NSSet *set1 = [NSSet setWithObjects:@"Apple", @"Banana", @"Cherry", nil];

使用setWithObjects:方法,同样以nil结束参数列表。

也可以使用集合字面量:

NSSet *set2 = @[@"Red", @"Green", @"Blue"];
  1. 集合操作 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

  1. 定义与初始化 NSMutableSet是可变集合,允许动态添加和删除对象。初始化方式如下:
NSMutableSet *mutableSet1 = [NSMutableSet set];

创建一个空的可变集合。也可以基于现有集合创建:

NSSet *originalSet = @[@"One", @"Two", @"Three"];
NSMutableSet *mutableSet2 = [NSMutableSet setWithSet:originalSet];
  1. 添加与删除对象 addObject:方法用于向集合中添加对象:
NSMutableSet *fruitSet = [NSMutableSet set];
[fruitSet addObject:@"Apple"];
[fruitSet addObject:@"Banana"];

removeObject:方法用于删除集合中的对象:

[fruitSet removeObject:@"Banana"];

removeAllObjects方法可以清空集合中的所有对象:

[fruitSet removeAllObjects];

七、集合类的内存管理

  1. 对象所有权 在Objective - C中,集合类(NSArrayNSMutableArrayNSDictionaryNSMutableDictionaryNSSetNSMutableSet)对其包含的对象拥有强引用。这意味着当对象被添加到集合中时,集合会保留该对象,对象的引用计数会增加。当对象从集合中移除或集合被销毁时,集合会释放对对象的引用,对象的引用计数会减少。

例如:

NSMutableArray *array = [NSMutableArray array];
NSString *str = [[NSString alloc] initWithString:@"Hello"];
[array addObject:str];
// str的引用计数增加
[str release];
// 此时str不会被释放,因为array持有它
[array removeObject:str];
// str的引用计数减少
// 如果这是str的最后一个强引用,str会被释放
  1. 自动释放池 在使用集合类时,要注意自动释放池的作用。当向集合中添加自动释放的对象时,这些对象会在最近的自动释放池被排空时释放。例如:
@autoreleasepool {
    NSMutableArray *array = [NSMutableArray array];
    for (int i = 0; i < 1000; i++) {
        NSString *str = [NSString stringWithFormat:@"Object %d", i];
        [array addObject:str];
        // str是自动释放的对象
    }
    // 自动释放池排空时,str对象会被释放
}

合理使用自动释放池可以避免内存峰值,特别是在处理大量临时对象时。

八、集合类的遍历

  1. 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;
    }
}];
  1. 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);
}
  1. 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;
    }
}];

九、集合类的类型安全

  1. 泛型语法 从Xcode 7开始,Objective - C支持泛型语法,这可以提高集合类的类型安全性。例如,定义一个只包含NSString对象的数组:
NSArray<NSString *> *stringArray = @[@"Hello", @"World"];

这样,编译器会在编译时检查数组中是否只添加了NSString类型的对象。对于字典,也可以指定键和值的类型:

NSDictionary<NSString *, NSNumber *> *dict = @{@"count": @10, @"value": @20};
  1. 类型检查与转换 在没有使用泛型语法时,需要手动进行类型检查和转换。例如,从数组中获取对象并转换为正确的类型:
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);
    }
}

使用泛型可以减少这种手动类型检查和转换的工作量,同时提高代码的可读性和安全性。

十、集合类在实际项目中的应用

  1. 数据存储与管理 在iOS应用开发中,NSArrayNSDictionary常被用于存储和管理数据。例如,从服务器获取的JSON数据通常会被解析为NSArrayNSDictionary。假设我们从服务器获取了一个包含用户信息的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;
}
  1. 集合类与UI展示 在UI开发中,NSArray常与UITableViewUICollectionView结合使用。例如,我们有一个包含联系人姓名的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应用,对集合类的熟练使用都是必不可少的技能。