使用可空性注解或将区域标记为已注解,以控制将 Objective-C
声明导入 Swift
的方式。
概览
在 Objective-C
中,你可以使用可以为 null
的指针来处理对对象的引用,在 Objective-C
中称为 nil
。在 Swift
中,所有值——包括对象实例——都保证是非空的。相反,你表示一个可能会丢失的值,因为它包装在一个可选类型中。当你需要指示缺少某个值时,可以使用值 nil
。
你可以在 Objective-C
代码中注释声明以指示实例是否可以具有 null
或 nil
值。这些注释改变了 Swift
导入声明的方式。有关 Swift
如何导入未注释声明的示例,请考虑以下代码:
@interface MyList : NSObject
- (MyListItem *)itemWithName:(NSString *)name;
- (NSString *)nameForItem:(MyListItem *)item;
@property (copy) NSArray<MyListItem *> *allItems;
@end
Swift
将每个对象实例参数、返回值和属性作为隐式解包的可选类型导入:
class MyList: NSObject {
func item(withName name: String!) -> MyListItem!
func name(for item: MyListItem!) -> String!
var allItems: [MyListItem]!
}
标注单个声明的可空性
你可以在 Objective-C
代码中使用可空性注解来指定参数类型、属性类型或返回类型是否可为空。使用 nullable
、nonnull
和 null_resettable
属性来注释作为简单对象或 Block
指针的属性声明、参数类型和返回类型。如果没有为类型提供可空性信息,Swift 不会区分可选引用和非可选引用,并将该类型导入为隐式展开的可选类型。
此列表描述了 Swift
如何导入具有不同可空性注释的类型:
Nonnullable
——作为非可选类型导入,无论是直接注解还是通过包含在注解区域中。Nullable
——作为可选类型导入。- 没有可空性注解或带有
null_resettable
注解——作为隐式解包的可选值导入。
以下代码显示了注解后的 MyList
类型。这两个方法的返回类型被标注为可为空,因为如果列表不包含给定的列表项或名称,则方法返回 nil
。所有其他对象实例都被注解为非空。
@interface MyList : NSObject
- (nullable MyListItem *)itemWithName:(nonnull NSString *)name;
- (nullable NSString *)nameForItem:(nonnull MyListItem *)item;
@property (copy, nonnull) NSArray<MyListItem *> *allItems;
@end
通过这些注解,Swift
导入 MyList
类型而不使用任何隐式解包的可选值:
class MyList: NSObject {
func item(withName name: String) -> MyListItem?
func name(for item: MyListItem) -> String?
var allItems: [MyListItem]
}
nullable
和 nonnull
注解是 _Nullable
和 _Nonnull
注释的简化形式,你几乎可以在任何上下文中使用 const
关键字和指针类型。复杂的指针类型,例如 id *
,必须使用这些注解进行显式标注。例如,要指定指向可空对象引用的不可空指针,请使用 _Nullable id * _Nonnull
。
将区域注释为 nonnull
你可以通过将整个区域标记为已检查可空性来简化注释 Objective-C
代码的过程。在由 NS_ASSUME_NONNULL_BEGIN
和 NS_ASSUME_NONNULL_END
宏划分的一段代码中,你只需要注释可空类型声明。宏包裹区域内未注释的声明被视为不可为空。
将 MyList
声明标记为已检查可空性可减少所需注释的数量。Swift
导入类型的方式与上一节相同。
NS_ASSUME_NONNULL_BEGIN
@interface MyList : NSObject
- (nullable MyListItem *)itemWithName:(NSString *)name;
- (nullable NSString *)nameForItem:(MyListItem *)item;
@property (copy) NSArray<MyListItem *> *allItems;
@end
NS_ASSUME_NONNULL_END
请注意,typedef
类型不假定为 nonnull
,即使在宏包裹区域内也是如此,因为它们本质上不是可以为空的。