Leg*_*ess 144 nullable objective-c objective-c-nullability
使用Xcode 6.3,引入了新的注释,以便更好地表达Objective-C中API的意图(并确保更好的Swift支持).那些注释当然是nonnull,nullable和null_unspecified.
但是使用Xcode 7,会出现很多警告,例如:
指针缺少可为空类型说明符(_Nonnull,_Nullable或_Null_unspecified).
除此之外,Apple使用另一种类型的可为空性说明符,标记其C代码(源代码):
CFArrayRef __nonnull CFArrayCreate(?CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);
总而言之,我们现在拥有这3种不同的可空性注释:
nonnull,nullable,null_unspecified_Nonnull,_Nullable,_Null_unspecified__nonnull,__nullable,__null_unspecified即使我知道为什么以及在哪里使用哪个注释,我也会对我应该使用哪种类型的注释,在哪里以及为什么感到困惑.这是我可以收集的:
nonnull,nullable,null_unspecified.nonnull,nullable,null_unspecified.__nonnull,__nullable,__null_unspecified._Nonnull,_Nullable,_Null_unspecified.但我仍然感到困惑的是,为什么我们有这么多的注释基本上做同样的事情.
所以我的问题是:
这些注释之间的确切区别是什么,如何正确放置它们以及为什么?
Cri*_*tik 141
从clang 文档:
nullability(type)限定符表示给定指针类型的值是否为null(
_Nullable限定符),null(限定符)没有定义的含义_Nonnull,或者null的目的不明确(_Null_unspecified限定符) .因为可空性限定符在类型系统中表达,所以它们比nonnull和returns_nonnull属性更通用,允许表达(例如)可空指针到非空指针数组.可为空性限定符写在它们应用的指针的右侧.
,和
在Objective-C中,可以使用上下文相关的非强制关键字在Objective-C方法和属性中使用可替换限定符的替代拼写.
因此,对于方法的返回值和参数,你可以使用双强调版本__nonnull/ __nullable/ __null_unspecified的,而不是任何单一强调的,或代替非强调的.不同之处在于单引号和双引号需要放在类型定义之后,而非下划线的则需要放在类型定义之前.
因此,以下声明是等效的并且是正确的:
- (nullable NSNumber *)result
- (NSNumber * __nullable)result
- (NSNumber * _Nullable)result
Run Code Online (Sandbox Code Playgroud)
对于参数:
- (void)doSomethingWithString:(nullable NSString *)str
- (void)doSomethingWithString:(NSString * _Nullable)str
- (void)doSomethingWithString:(NSString * __nullable)str
Run Code Online (Sandbox Code Playgroud)
对于属性:
@property(nullable) NSNumber *status
@property NSNumber *__nullable status
@property NSNumber * _Nullable status
Run Code Online (Sandbox Code Playgroud)
然而,当涉及返回与void不同的东西的双指针或块时,事情变得复杂,因为这里不允许使用非下划线的:
- (void)compute:(NSError * _Nullable * _Nullable)error
- (void)compute:(NSError * __nullable * _Null_unspecified)error;
// and all other combinations
Run Code Online (Sandbox Code Playgroud)
与接受块作为参数的方法类似,请注意nonnull/ nullablequalifier适用于块,而不是其返回类型,因此以下内容是等效的:
- (void)executeWithCompletion:(nullable void (^)())handler
- (void)executeWithCompletion:(void (^ _Nullable)())handler
- (void)executeWithCompletion:(void (^ __nullable)())handler
Run Code Online (Sandbox Code Playgroud)
如果块具有返回值,那么您将被强制进入下划线版本之一:
- (void)convertObject:(nullable id __nonnull (^)(nullable id obj))handler
- (void)convertObject:(id __nonnull (^ _Nullable)())handler
- (void)convertObject:(id _Nonnull (^ __nullable)())handler
// the method accepts a nullable block that returns a nonnull value
// there are some more combinations here, you get the idea
Run Code Online (Sandbox Code Playgroud)
作为结论,您可以使用任何一个,只要编译器可以确定要为其分配限定符的项目.
Ben*_*mas 26
来自Swift博客:
此功能首先在Xcode 6.3中发布,关键字为__nullable和__nonnull.由于与第三方库的潜在冲突,我们已将Xcode 7中的它们更改为您在此处看到的_Nullable和_Nonnull.但是,为了与Xcode 6.3兼容,我们预定义了宏__nullable和__nonnull以扩展为新名称.
kga*_*dis 24
我真的很喜欢这篇文章,所以我只是展示了作者所写的内容:https: //swiftunboxed.com/interop/objc-nullability-annotations/
null_unspecified:桥接到Swift隐式解包的可选项.这是默认值.nonnull:价值不会是零; 桥接到常规参考.nullable:价值可以是零; 桥接到可选.null_resettable:读取时,值永远不能为零,但您可以将其设置为nil以重置它.仅适用于属性.无论您是在属性或函数/变量的上下文中使用它们,上面的符号都会有所不同:
该文章的作者也提供了一个很好的例子:
// property style
@property (nonatomic, strong, null_resettable) NSString *name;
// pointer style
+ (NSArray<NSView *> * _Nullable)interestingObjectsForKey:(NSString * _Nonnull)key;
// these two are equivalent!
@property (nonatomic, strong, nullable) NSString *identifier1;
@property (nonatomic, strong) NSString * _Nullable identifier2;
Run Code Online (Sandbox Code Playgroud)
Wil*_*iuk 12
非常方便
NS_ASSUME_NONNULL_BEGIN
Run Code Online (Sandbox Code Playgroud)
和关闭
NS_ASSUME_NONNULL_END
Run Code Online (Sandbox Code Playgroud)
这将使代码级别'nullibis'的需要无效:-)因为除非另有说明,否则假设所有内容都是非null(或nonnullor _nonnull或__nonnull)是有意义的.
不幸的是,这也有例外......
typedefs不被认为是__nonnull(注意,nonnull似乎不起作用,必须使用它的丑陋的同父异母兄弟)id *需要一个明确的无效,但哇罪孽(_Nullable id * _Nonnull< - 猜这是什么意思......)NSError ** 总是假定可以为空因此,除了例外情况和不一致的关键字引出相同的功能之外,也许方法是使用丑陋的版本__nonnull/ __nullable/ __null_unspecified并在编译器抱怨时交换...?也许这就是为什么它们存在于Apple标题中?
有趣的是,有些东西把它放到我的代码中...我厌恶代码中的下划线(旧式的Apple C++风格的家伙)所以我绝对相信我没有输入这些但是它们出现了(几个例子):
typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * __nullable credential );
Run Code Online (Sandbox Code Playgroud)
更有趣的是,它插入__nullable的地方是错误的...(eek @!)
我真的希望我可以使用非下划线版本,但显然不会与编译器一起使用,因为这被标记为错误:
typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential * nonnull credential );
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
35662 次 |
| 最近记录: |