Objective-C关键字__Nullable和__Nonnull

来源:互联网 发布:网络电视机顶盒选购 编辑:程序博客网 时间:2024/05/23 01:16

Xcode 6.3中有一项新特性,`nullability`标记,这为 OC 提供了类似 Swift 中的 Optional 的类型为了让更多开发者从 OC 向 Swift 过渡,OC 和 Swift 混编已经变得尤为重要,就像是OC通向Swift的一座桥梁,通过引入泛型使得 OC 和 Swift 之间更加安全清楚的理解和共享包含特定元素的集合

The Core: _Nullable and _Nonnull

关于 _Nullable 和 _Nonnull ,官方文档有这么一句话
At the core of this feature we have two new type annotations: _Nullable and _Nonnull.
As you might expect, a _Nullable pointer may have a NULL or nil value, while a _Nonnull one should not.
The compiler will tell you if you try to break the rules.

大概意思就是,我们又添加了两种类型,_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!

事实上你可以在任何可以使用C语言关键字const的地方使用_Nullable_Nonnull
当然 _Nullable_Nonnull 一般用于指针类型,在一般情况下,有一个更好的方法去实现这种标记的功能
。即在方法申明的时候可以使用non-underscored形式,nullablenonnull,直接写在类型前面(类型必须是一个对象或者block指针)。

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

在属性中,同样可以使用non-underscored形式将这样的关键字放到属性列表中

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

non-underscored方式比underscored方式有很明显的优势,但是即便如此,你仍然需要将它们写在每一种类型中去
为了更加高效的工作和代码的简洁,我们需要用到一种苹果称之为audited regions的方法

什么是 Audited Regions

为了方便采用新的方式,你可以在Objective-C头文件标记一块区域作为audited for nullability,在这块区域内,
任何简单指针类型都将被标注为nonnull类型,这样一来,如果有一大段代码需要加注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;// ...@endNS_ASSUME_NONNULL_END// --------------self.list.name = nil;   // okayAAPLListItem *matchingItem = [self.list itemWithName:nil];  // warning!

安全起见,这种方式会有一些异常

1.typedef类型不会被当做nonnull处理,即使在audited regions
2.很多复杂的指针,譬如id *必须明确标注,例如要制定一个非空的指针可以被空对象引用,要这样写_Nullable id * _Nonnull
3.特定类型 NSError ** 经常通过方法的参数返回错误以致它总是被假定为一个可以被空指针引用的空指针

兼容性

如果已经存在的Objective-C代码被重写会怎样?单单以这种方式改变类型安全么?没错,是安全的。

现有的编译代码会在你的框架上继续跑,即ABI不会变,就是说现有的代码在运行时出现nil不会报错
当你使用新的Swift编译器,使用不安全的方式在编译时现有的源代码在你的框架可能会有额外的警告
nonnull不影响优化,尤其是在运行时你仍然能检查标注为nonnull的参数是否是nil,向后兼容是很重要的。

这个功能最早被发布在Xcode 6.3上,关键字是__nullable__nonnull,由于一些三方库潜在的冲突,
Xcode 7上将关键字改为这里提到的_Nullable_Nonnull,为了兼容Xcode 6.3,苹果定义了
__nullable__nonnull

回到Swift

现在我们已经nullability标注添加到我们的Objective-C头文件中,来看看怎么在Swift中使用它
在没有添加标注前的Objective-C转换成Swift应该是这样的

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代码看起来就简洁多了,虽然是一个微妙的变化,但这会让你的框架更完美

2 0
原创粉丝点击