Swift Nullability and Objective-C

简介: 通过Bridging-Header文件,Swift可以与Objective-C无缝调用,但是Swift与Objective-C有一个很大的不同点:Swift支持Optional类型。

通过Bridging-Header文件,Swift可以与Objective-C无缝调用,但是Swift与Objective-C有一个很大的不同点:Swift支持Optional类型。比如NSViewNSView?,在Objective-C里对此只有一种表示,即NSView *,既可以用来表示该View为nil、也能表示为非nil,此时Swift编译器是无法确定这个NSView是不是Optional类型的,这种情况下Swift编译器会把它当作NSView!处理,隐式拆包。

在早期发布的Xcode版本中,苹果的一些框架针对Swift的Optional类型进行了一些专门审查,使他们的API能够适配Optional,而Xcode 6.3的发布,给我们带来了Objetive-C的一个新特性:nullability注解,利用该特性我们也能对自己的代码进行类似的处理。

核心:__nullable 和 __nonnull

这个功能给我们带来了两个新的类型注解:__nullable__nonnull,就像你看到的,__nullable可以表示一个NULL或者nil值,而__nonnull则刚好相反。如果你违反了这个规则,你将会收到编译器的警告:

@interface AAPLList : NSObject <NSCoding, NSCopying>
//---
- (AAPLListItem * __nullable)itemWithName:(NSString * __nonnull)name;
@property (copy, readonly) NSArray * __nonnull allItems;
//---
@end

//--------------

[self.list itemWithName:nil]; // warning!

你能在任何地方使用__nullable__nonnull关键字,比如和标准C的const一起使用,也能直接应用到指针上。但是在大多数情况下,你会以优雅的方式写下这些注解:在方法定义或声明里,只要类型是一个简单的对象或者Block指针,你就能以不带下划线的方式(nullablenonnull)直接写在左括号后面:

- (nullable AAPLListItem *)itemWithName:(nonnull NSString *)name;
- (NSInteger)indexOfItem:(nonnull AAPLListItem *)item;

对于@property,你也能以同样的方式写在它的属性列表里:

@property (copy, nullable) NSString *name;
@property (copy, readonly, nonnull) NSArray *allItems;

不带下划线的形式比带下划线的形式看起来更简洁,但你仍然需要将它们应用到头文件的每一个类型里。如果你觉得麻烦同时想让头文件变得更加简洁,你就会使用到审查区域。

审查区域(Audited Regions)

如果想更加轻松的添加这些注解,那么你可以把Objective-C头文件的某个区域标记为需要审查(for nullability),在这个区域内,所有简单的指针类型都会被当作nonnull,我们之前的例子会变成这样:

NS_ASSUME_NONNULL_BEGIN
@interface AAPLList : NSObject <NSCoding, NSCopying>
//---
- (nullable AAPLListItem *)itemWithName:(NSString *)name;
- (NSInteger)indexOfItem:(AAPLListItem *)item;

@property (copy, nullable) NSString *name;
@property (copy, readonly) NSArray *allItems;
//---
@end
NS_ASSUME_NONNULL_END

// --------------

self.list.name = nil;   // okay

AAPLListItem *matchingItem = [self.list itemWithName:nil];  // warning!

Xcode 6.3(iOS 8.3 SDK)引入了NS_ASSUME_NONNULL_BEGIN / END
其中itemWithName方法的name参数没有使用Nullability特征,但是会被当作nonnull处理

为了安全起见,这个规则也有一些例外情况:

  • typedef定义的类型不会继承nullability特性—它们会轻松地根据上下文选择nullable或non-nullable,所以,就算是在审查区域内,typedef定义的类型也不会被当作nonnull
  • id *这样更复杂的指针类型必须被显式地注解,比如,你要指定一个nonnull的指针为一个nullable的对象引用,那么需要使用__nullable id * __nonnull
  • NSError **这些特殊的、通过方法参数返回错误对象的类型,将总是被当作是一个nullable的指针指向一个nullable的指针:__nullable NSError ** __nullable

你可以通过Error Handling Programming Guide了解更多详细内容。

兼容性

你的Objective-C框架现有的代码写对了吗?是否能安全的改变它们的类型? Yes, it is.

  • 现有的、被编译过的代码还能继续使用你的框架,也就是说ABI没有变化(编译器不会报错),这也意味着现有的代码不会在运行时捕获到nil的不正确传值。
  • 用新的Swift编译器编译现有的源码,并在使用你的框架的时候,可能会因为一些不安全的行为在编译时得到额外的警告。
  • nonnull不影响优化,尤其是你还可以在运行时检查标记为nonnull的参数是否为nil,这可能需要必要的向后兼容。

大多数情况下,应该接受nullablenonnull,你当前所使用的断言或者异常太粗暴了:违反约定是程序员经常犯的错误(而nullablenonnull能在编译时就解决问题)。特别的,返回值是你能控制的东西,永远不应该对一个non-nullable的返回类型返回一个nil,除非这是为了向后兼容。

回到Swift

现在我们给我们的Objective-C头文件添加了nullability注解,我们在Swift中使用它:
在Objective-C中添加注解之前:

class AAPLList : NSObject, NSCoding, NSCopying { 
    //---
    func itemWithName(name: String!) -> AAPLListItem!
    func indexOfItem(item: AAPLListItem!) -> Int

    @NSCopying var name: String! { get set }
    @NSCopying var allItems: [AnyObject]! { get }
    //---
}

添加注解之后:

class AAPLList : NSObject, NSCoding, NSCopying { 
    //---
    func itemWithName(name: String) -> AAPLListItem?
    func indexOfItem(item: AAPLListItem) -> Int

    @NSCopying var name: String? { get set }
    @NSCopying var allItems: [AnyObject] { get }
    //---
}

这些Swift代码非常清晰。只有一些细节的变化,但是它让你的框架使用起来更爽。

目录
相关文章
|
5月前
|
安全 编译器 Swift
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
310 2
|
12月前
|
编译器 Swift iOS开发
44 Swift和Objective-C的运行时简介
Swift和Objective-C的运行时简介
86 0
|
1月前
|
设计模式 前端开发 Swift
探索iOS开发:Swift与Objective-C的较量
在这篇文章中,我们将深入探讨iOS开发的两大编程语言——Swift与Objective-C。我们将分析这两种语言的特性、优势和局限性,并讨论它们在现代iOS开发中的应用。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和建议。
41 3
|
5月前
|
算法 编译器 Swift
【Swift开发专栏】Swift与Objective-C的对比
【4月更文挑战第30天】Swift与Objective-C对比:Swift语法简洁,支持元组、泛型和闭包,提高可读性;性能优化,使用LLVM编译器,与Objective-C兼容,便于迁移项目;生态系统活跃,苹果官方支持,丰富资源库。Objective-C虽历史悠久,但逐渐边缘化。对于新项目和开发者,Swift是更佳选择,驱动iOS开发创新。
345 0
|
5月前
|
安全 JavaScript 前端开发
IOS开发基础知识:介绍一下 Swift 和 Objective-C,它们之间有什么区别?
IOS开发基础知识:介绍一下 Swift 和 Objective-C,它们之间有什么区别?
196 0
|
12月前
|
安全 程序员 编译器
2 Swift 和 Objective-C的区别
Swift 和 Objective-C的区别
91 0
|
前端开发 JavaScript Go
2022 软件工程师状况报告:Go 最抢手|开发者最“嫌弃” PHP、Swift、Scala/R/Objective-C
2022 软件工程师状况报告:Go 最抢手|开发者最“嫌弃” PHP、Swift、Scala/R/Objective-C
175 0
2022 软件工程师状况报告:Go 最抢手|开发者最“嫌弃” PHP、Swift、Scala/R/Objective-C
|
SQL 前端开发 JavaScript
2021最受欢迎的编程语言排行:苹果编程语言Objective-C被Swift取代
苹果公司的Objective-C最终退出了Tiobe跟踪的流行编程语言的前20名,但是「恐龙」语言却获得了意想不到的推动,Swift语言取代Objective-C的时代要来了。
356 0
2021最受欢迎的编程语言排行:苹果编程语言Objective-C被Swift取代
|
自然语言处理 Go iOS开发
iOS开发者知识普及,Swift 挑战 Objective-C,谁会笑到最后?
如果你的公司也正计划跟随 iOS 软件开发,那么你需要作出一个至关重要的决定。你需要为你的产品选择合适的技术组合。你的目标是什么?如果是原生应用开发而不是跨平台软件,你会选用哪种编程语言?久经考验的 Objective-C 还是 Swift?