如何在基于块的 API 方法中使用非空和可为空的 Objective-C 关键字
Posted
技术标签:
【中文标题】如何在基于块的 API 方法中使用非空和可为空的 Objective-C 关键字【英文标题】:How to use nonnull and nullable Objective-C keywords in block-based API method 【发布时间】:2015-06-21 06:39:55 【问题描述】:考虑以下方法
- (void)methodWithArg:(NSString *)arg1 andArg:(NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
使用新的nonnull
和nullable
annotation keywords,我们可以如下丰富它:
- (void)methodWithArg:(nonnull NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
但我们也收到此警告:
指针缺少可空性类型说明符(__nonnull 或 __nullable)
它指的是第三个参数(块一)。
documentation 没有举例说明如何指定块参数的可空性。它逐字说明
您可以立即使用非下划线形式 nullable 和 nonnull 在左括号之后,只要类型是简单对象或 块指针。
我尝试将块的两个关键字之一(在任何位置)放置,但没有任何运气。还尝试了下划线前缀的变体(__nonnull
和 __nullable
)。
因此我的问题是:如何为块参数指定可空性语义?
【问题讨论】:
【参考方案1】:这似乎有效
- (void)methodWithArg:(nonnull NSString *)arg1
andArg:(nullable NSString *)arg2 completionHandler:(nullable void (^)
(NSArray * _Nullable results, NSError * _Nonnull error))completionHandler
您需要为块及其参数指定可空性...
编辑:有关详细信息,请参阅Swift Blog
【讨论】:
NSError **
类型如何工作?我似乎无法让编译器满意。
据swift博客:The particular type NSError ** is so often used to return errors via method parameters that it is always assumed to be a nullable pointer to a nullable NSError reference.
developer.apple.com/swift/blog/?id=25
@duhanebel 答案在***.com/questions/33198597/…中给出:(NSError * _Nullable *_Nullable) 错误【参考方案2】:
这是我用于 NSError ** 案例的内容:
-(BOOL) something:(int)number withError:(NSError *__autoreleasing __nullable * __nullable)error;
【讨论】:
正如Apple 所说,对于NSError **
,您无需指定其可空性。【参考方案3】:
为了在头文件中定义完成,我这样做了
typedef void (^PublicEventsHandler) (BOOL success, NSArray * _Nullable publicEvents);
当然,我同意接受的答案。
【讨论】:
【参考方案4】:来自苹果developer blog:核心:_Nullable 和 _Nonnull
您可以使用不带下划线的形式 可空和非空紧跟在左括号之后,只要 类型是一个简单的对象或块指针。
不带下划线的形式比带下划线的更好,但是 您仍然需要将它们应用于标题中的每种类型。
【讨论】:
是的,但非下划线(更好)的在块声明中不起作用【参考方案5】:你也可以这样做:
- (id __nullable)methodWithArg:(NSString * __nullable)arg1
andArg:(NSString * __nonnull)arg2
completionHandler:(void (^ __nonnull)(NSArray * __nonnull results, NSError * __nullable error))completionHandler;
这仅取决于您更喜欢哪种语法。
【讨论】:
您能详细说明一下您定义的含义吗?我是否正确地认为此方法需要代码块,并且不能为零?我试图在最后一个括号 NSError * __nullable error) _Nonnull )completionHandler; 之前添加 _Nonnull并得到了一个令人讨厌的编译器错误。【参考方案6】:根据Apple Blog ("Nullability and Objective-C"), 你可以使用
NS_ASSUME_NONNULL_BEGIN
和 NS_ASSUME_NONNULL_END
。
在这些区域内,任何简单的指针类型都将被假定为nonnull
。然后你可以为可空对象添加nullable
,就像
NS_ASSUME_NONNULL_BEGIN
@interface MyClass: NSObject
- (void)methodWithArg:(NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
@end
NS_ASSUME_NONNULL_END
如果error是NSError **
类型,应该是NSError * _Nullable * _Nullable
如果对象是id *
类型,最好使用id _Nullable * _Nonnull
,这取决于(可能你想要_Nullable id * _Nullable
类型)。
如果对象是NSObject *
类型,则需要在指针后面加上注解,比如NSObject * _Nullable * _Nonnull
注意
_Nonnull
和_Nullable
应该在指针或id
之后使用(Apple 在示例代码AAPLListItem * _Nullable
中使用),但非下划线形式nonnull
和nullable
可以在左括号之后使用。
但是,在常见的情况下,有一种更好的方法来编写这些 注释:在方法声明中,您可以使用 非下划线形式
nullable
和nonnull
在打开之后立即 括号,只要类型是简单的对象或块指针。
在"Nullability and Objective-C"查看更多信息
为了安全起见,这条规则有一些例外:
typedef
类型通常不具有固有的可空性——它们可以 根据上下文很容易可以为空或不可为空。 因此,typedef
类型不假定为nonnull
,即使在 被审计的地区。 必须使用更复杂的指针类型,例如id *
明确注释。例如,指定一个不可为空的指针 对于可为空的对象引用,请使用_Nullable id * _Nonnull
。 特定类型NSError **
经常用于通过以下方式返回错误 方法参数,它总是被假定为一个可为空的指针 到一个可以为空的NSError
引用。
_Nullable id * _Nonnull
可以混淆,id _Nullable * _Nonnull
更好理解。
_Nonnull
和_Nullable
应该在指针或id
之后使用(Apple 在示例代码中使用AAPLListItem * _Nullable
)
【讨论】:
对于弱属性,应用_Nullable。以上是关于如何在基于块的 API 方法中使用非空和可为空的 Objective-C 关键字的主要内容,如果未能解决你的问题,请参考以下文章