【问题标题】:Should we write `[NSMutableArray<NSString *> array]`?我们应该写 `[NSMutableArray<NSString *> array]` 吗?
【发布时间】:2016-01-08 12:20:44
【问题描述】:

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 的返回值提供任何编译时保证。那么泛型对那些人来说总是没用吗?

【问题讨论】:

  • 如果您不确定数组将容纳什么样的对象,为什么要放松 Objective-C 的动态性?
  • 这个答案或许能帮到你:stackoverflow.com/a/5198040/3222713
  • 感谢@Pipiks,我理解为使用轻量级打字。
  • @AnoopVaidya 不知道数组将容纳的事物类型不是一般情况,可能是糟糕的设计。
  • 对于&lt;NSString *&gt;,项目应该是@"...",对于&lt;NSNumber *&gt;,项目应该是@(...),这就是你收到警告的原因,尽管你添加了NSNumber定义数组的项类型为NSString

标签: objective-c generics nsarray xcode7


【解决方案1】:

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

  • 有些类型检查总比没有好
  • 使代码更具自我记录性
  • Xcode 的未来版本可以改进类型推断
  • 它已经与 Swift 顺利集成——随着时间的推移,它只会变得更加重要

缺点:

  • 没有发现 100% 的错误 -- 但有什么作用?
  • 为您的代码添加一些额外的内容

总而言之:目前略有改进,但使您的代码更具前瞻性。

【讨论】:

    【解决方案2】:

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

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

    还有希望在未来版本的编译器中类型检查会有所改进。

    但总的来说,在数组中意外混合类型并没有问题,这样的错误往往会显示开发人员的困惑。如果我有一个 Motorcycle 对象数组并添加了一个 Juggler 对象,我可能会遇到严重的设计不匹配错误或严重混乱。

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

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

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

    【讨论】:

    • 文档位非常重要,即使没有检查,仍然值得使用泛型。
    • 我想到了一个实现,假设我有一个NSView 并且我循环遍历所有子视图,它可能包含NSButtonNSTextFieldNSBoxNSView 等。那么未来将如何做到这一点呢?这真的是设计缺陷吗?
    • 这是一个糟糕的例子,因为它们都是NSView 的子类,它是NSView 对象的数组。输入NSNumber 是不合适的。
    • 减少荒谬?
    • 我见过很多错误,人们把错误的东西放在数组中。在我的经验中,最常见的是当有模型和视图模型时(这特别糟糕,因为它们通常具有许多相同的方法,因此通常可以“工作”)。对于一个团队来说,一个特别臭名昭著的例子是一个同时具有PersonPersonRecord 类的系统。有人会制作PersonRecords 的数组并调用变量people,后来的维护者会犯你想象的错误。仔细命名是如此重要,但泛型会为我们省去很多麻烦。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2010-11-02
      • 2011-04-21
      • 1970-01-01
      • 2011-04-27
      • 2014-03-17
      • 2011-07-29
      • 1970-01-01
      • 2017-06-13
      • 2019-10-02
      相关资源
      最近更新 更多