Objective-C 2015新特性

2,084 阅读6分钟
原文链接: ios.jobbole.com

刚开始做iOS开发的那些日子。 我仍然记得几年前买的那些老书籍。现在他们静静的躺在我办公室的书架上。多年前我虔诚的翻阅它们的时候,我不禁担心Objective-C做不到什么而不是它能做到的事。 今年(Objective-C)能做更多事了。本周我们会看到一个成熟的老朋友。让我们来看下Objective-C有什么提高吧。

设置

朋友们,让我们去那条走过很多次的小道散散步。

@property (strong, nonatomic) NSArray *someViews;

这是一个熟练的Objective-C开发者的标准写法。表示包含一些视图的集合属性。但是有一些内在的缺陷隐藏在这一小段代码中。 它可以返回空吗? 除非有文档说明或者这个开发者在现场,我们不能单凭看这些代码得到答案。 这里面除了UIView类型对象之外还有其他类型的对象吗? 和上面类似,谁知道呢?或许可以使用反射做判断(译者注:这里指的是isKindOfClass之类的方法)?或者这里能有除了UIView之外的对象吗?或者说UIView的任何子类? 看起来这会需要很多转换 因为这是包含某些对象的数组,当某人找出这个数组里面对象类型——用它来做一些事时会花费很长的时间。 这削弱了Swift代码和可读性 不幸的是,Swift有泛型。这意味着,一个集合类型被看做可选的任意对象类型。当使用这个属性的时候,(这个特点)强迫开发者对Swift和Objective-C进行转换。

可空注释

当你知道一个简单的属性会引起这么多问题时可能有点不舒服。维护有潜在问题的代码更容易出错,更别提在上述语言和一个新的语言(如Swift)之间交互了。 能够让这件事变的简单的第一步是我最喜欢的Objective-C新特性——可空注释。这些注释在编程中提供了一些非常有价值的东西。 意图 他们详细地描述了一个API。能返回空(nil),不能返回空。简单来说,可以避免花几个小时在调试上。有三个可用值:

  • nullable(可以为 nil 或 NULL)——对应(在Swift中的使用方式)’ UIView?’
  • nonnull (不为 nil,如果传 nil 给该指针,将会收到编辑器的警告)——对应(在Swift中的使用方式)’UIView’
  • null_unspecified(是否为 nil 是不确定的)——对应(在Swift中的使用方式)’UIView!’

让我们再看一下例子中的那个属性。假设这个属性是用来在运行时创建一些用户界面的迭代器。这种情况下,这里应该存放的是一些按钮和视图。 但是天呐——他们在任何情况下都不应该为空。现在应该这样写:

@property (strong, nonatomic, nonnull) NSArray *someViews;

不仅这对Objective-C有帮助,现在这个属性也使得Swift里不再到处是optionals。 开发者看到这些代码就知道它是不是会返回空指针。好极了。 我们已经改良了静态检查、Swift的可用性以及这些API使用时最重要的意图。

泛型

全世界使用Objective-C的开发者都很高兴。哎呀,泛型遍布各地,这些应该归功于勇敢的开发者。 如果Cocoa Touch是孩子的睡前故事并且Objective-C是主人公,这本书肯定以上面几句话结尾。长期以来,泛型的缺席一直是很多开发者的痛处。 尽管用了32年,Objective-C现在有泛型了。尽管沉浸在Swift 2 发布的喜悦中,WWDC 15的参会者和消费者等不应该轻视这个消息。它代表了很多改变,而且大多都是积极的。 回到我们的属性。我们现在可以写下来告诉编译器和开发者这里要求的是UIView。

@property (strong, nonatomic, nonnull) NSArray *someViews;

这很好,因为如果一个人试着把除了UIViews之外的对象赋值给这个属性,那么编译器会提示和警告。这也会省去了一些头疼的转换。 Swift也很高兴。在最近的更新中,我们让Swift知道一些对象不是可选的。现在Swift也知道这里面包含了UIView,所以可以摆脱任何有歧义的对象声明。 开发者可以像C#、C++、Swtft以及其他语言一样,使用<>括号标识类型。虽然这(符号)代表了遵循协议一致性,编译器经过推断知道何时、何地、如何运用它们。 长远来看,参数化扩展(extensions)、类目(categories)和类(classes)也会成为可能。带来的好处不仅在集合类。泛型这个特性可以用在Objective-C的任何地方,容器类只是其中之一。例如,看着下面的NSDictionary 类会让你展开微笑:

@interface NSDictionary (Lookup)
- (nullable ObjectType)objectForKey:(KeyType)aKey;
@end

尽管在我知道泛型是通过类型擦除来实现时有点失望,考虑到Objective-C老代码中大量遗留问题你就会懂(为什么这样做)。 类型擦除实现了二进制兼容,它也允许不改变Objective-C运行时。所以亲爱的开发者,皱皱眉头,抱怨一下C#的泛型实现确实比任何其他语言都好,我们还是要接着工作。

KindOf 类型

哎,我们的旅行还剩重要的一步。回忆一下我们提到可以包UIView的属性。所以,正常情况下能推断这里面包含了一些视图和按钮。 有了这些,当有人写出下面这样的代码时会发生什么呢:

[self.someViews[0] addTarget:self action:selector(aMethod:) forControlEvents:UIControlEventTouchUpInside];

啊,一个编译器警告。 这很正常,因为尽管在这个属性中插入一个按钮是有效的,并且你也可以说它是一个视图,在转换前无法确定它就是一个按钮。 这种情况比想象中发生的要多,利用KindOf新特性很容易解决这个问题。回到这个例子中的属性。

@property (strong, nonatomic, nonnull) NSArray<__kindof UIView *> *someViews;

实际上,我们告诉编译器这个属性和它的容器可以包含UIView类型的对象。类型契约中支持了更多的我们以前没有的类型信息。 其本质是什么?向下转型。 这意味着代码在编译器上运行良好,因为编译器知道肯定有一个按钮在容器内。 现在,如果你再回头看最初的担心,他们都被搞定了。 当Swift否定者对(Objective-C)的价值大加赞赏时,他们也应该心存感激。因为(Objective-C语言)价值的提升基于一点:Swift的交互性。 尽管如此,在一些特殊的场合,Objective-C是比以前更强大。

总结

Objective-C是我编程生涯的初恋。它是与众不同(到现在仍是),它的显著优点以及缺点都让我着迷。现在Swift快速赢得了我这颗编程之心,我仍然发现我在使用Objective-C时很快乐。这些新特性很受欢迎。它们能够被用来编写更好的代码,并且它们已经在Foundation框架中随处可见了。