Generics 泛型

我们直接来看一段代码:

NSArray *names = @[@"Sophie", @"Alexandra", @"Charlotte",
@"Isabella"];
for (NSString *name in names) {
    NSLog(@"%@ is %ld letters.", name, [name length]);
}

在这一段代码中,我们创建了一个表示姓名的字符串数组,并且遍历了他,把每一个名字的长度打印了出来,现在我们再来看下面的这段代码:

NSArray *numbers = @[@42, @556, @69, @3.141];
for (NSString *number in numbers) {
    NSLog(@"%@ is %ld letters.", number, [number length]);
}

在这段代码里,我们创建了一个数字数组,同样遍历了这个数组,并且把每一个数字的长度打印了出来。

等等,是不是哪里不对?在 numbers 数组里,所有的数字其实是 NSNumber 类,而不是 NSString 类。代码错了吧?

代码确实是错的,但这里 Xcode 没有报错,这是因为我把 NSNumber 对象放进了数组,但用 NSString 的形式循环了它。这样的代码在编译时是可以通过,但是运行时程序就会崩溃。

Swift 里引入了一个「泛型」概念来解决上面这个问题。但是当年苹果推出 Swift 时, Objective-C 里是没有「泛型」这个概念的。

好在到现在已经有了,但是没有在 Swift用的爽。这个概念是用了一个叫做「类型擦除」的黑科技,但是这是黑科技诶。稍有不慎,就会导致代码报错,程序崩溃。

提示归提示,我们还是要具体看看在 Objective-C 里泛型是怎么用的。

首先创建一个数组,并且声明这个数组只能存某一类型的数据,那当你添加其他类型的数据到这个数组里时, Xcode 就会报错。

NSMutableArray<NSString *> *names = [NSMutableArray
arrayWithCapacity:4];
[names addObject:@"Sophie"];
[names addObject:@42];

细心的你会发现, 这里有一个空格。这个空格并不是一定要有的,但是有这个空格会让代码的可读性变得更强。

第二步,你可以尝试着把这个数组里的某个数取出来,并且把它用另一种数据形式保存起来。

NSNumber *number = names[0];

那现在就可以重新写一下我们之前无法运行的那个例子了:

NSArray<NSNumber *> *numbers = @[@42, @556, @69, @3.141];
for (NSString *number in numbers) {
 NSLog(@"%@ is %ld letters.", number, [number length]);
}

你就会发现,现在这段代码就可以运行了。在这个泛型的数组里,你可以放泛型数组、字典或者集合,都是有效的。

要注意的是,如果你要用字典,要用下面的这种特殊的方式来声明,关键字和值:

NSDictionary<NSString *, NSNumber *> *villains = @{ @"Daleks": @100,
@"Cybermen": @80 };

所以到现在我们可以得出以下的结论:第一 Objective-C 的泛型没有 Swift 里的好用。第二泛型这种新技术,并不会在大多数的项目用到。

results matching ""

    No results matching ""