我们应该写 `[NSMutableArray<NSString *> array]` 吗?

Should we write `[NSMutableArray<NSString *> array]`?

Xcode 7 引入了泛型。它允许提示,例如:

并允许警告,例如:

但是很多事情都失败了,根本没有任何警告:

NSMutableArray<NSNumber *> *array;
array = [NSMutableArray<NSNumber *> arrayWithObjects:@0, @"", nil];
NSLog(@"%@", [array[1] class]);// __NSCFConstantString
array = [NSMutableArray<NSNumber *> arrayWithContentsOfURL:[NSURL URLWithString:@"http://ios.eezytutorials.com/sample-files/sample-array-plist.plist"]];
NSLog(@"%@", [array[0] class]); // __NSCFString

所以键入通用创建有点不可靠。

问题:我们应该使用不可靠的语法吗?

NSMutableArray<NSString *> *array;
array = [NSMutableArray<NSString *> array];
array = [NSMutableArray<NSString *> arrayWithArray:array];
array = [NSMutableArray<NSString *> arrayWithObjects:@"", @"", nil];
array = [NSMutableArray<NSString *> arrayWithContentsOfURL:url];

或者简化语法?

NSMutableArray<NSString *> *array;
array = [NSMutableArray array];
array = [NSMutableArray arrayWithArray:array];
array = [NSMutableArray arrayWithObjects:@"", @"", nil];
array = [NSMutableArray arrayWithContentsOfURL:url];

我还担心,显然不可能为 arrayWithContentsOfURLarrayWithContentsOfFile 的 return 值提供任何编译时保证。那么泛型对那些人总是没用吗?

是的,应该使用泛型来为编译器和开发人员提供更多的类型规范信息。

提供数组将包含在声明中的对象类型至少是一种文档增益,错误检查是一个额外的好处。

也希望在未来版本的编译器中改进类型检查。

但一般来说,意外地在数组中混合类型并不是问题,此类错误往往表明开发人员的困惑。如果我有一个 Motorcycle 对象数组并添加一个 Juggler 对象,我要么有主要的设计不匹配错误,要么有严重的混淆。

最好的防御是class和变量命名,不是array而是motorcycleListjugglerList。然后,如果我有 motorcycleList addObject:juggler,很快就会发现在编写语句时出现错误。

添加到 ObjC 语言只是显式规范进程中的一个步骤:

id x = [NSMutableArray new];
NSMutableArray *list = [NSMutableArray new];
NSArray<NSString *> *stringList = [NSMutableArray new];

你说得对,Obj-C 中的泛型并不完美,但是:

  • 某些类型检查比 none
  • 更好
  • 使代码更加self-documenting
  • Xcode 的未来版本可以改进类型推断
  • 它已经使与 Swift 的集成变得顺畅了——随着时间的推移它只会变得越来越重要

缺点:

  • 没有发现 100% 的错误 -- 但有任何发现吗?
  • 给您的代码增加一些额外的麻烦

总而言之:现在略有改进,但会使您的代码更加 future-proof。

因为它确实会触发问题中描述的警告,所以使用具有指定泛型类型 ([NSMutableArray<NSString *> ...];) 的构造函数是更好的方法。

但我们可以假设 Objective-C 中引入泛型是为了过渡到 Swift,在这方面,直接使用 Swift 更好.