如何在基于块的 API 方法中使用非空和可空的 Objective-C 关键字

考虑以下方法

- (void)methodWithArg:(NSString *)arg1 andArg:(NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;

使用新的 nonnullnullable 注释关键字注释关键字,我们可以丰富它如下:

- (void)methodWithArg:(nonnull NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;

但我们也得到这样的警告:

指针缺少可为空的类型说明符(_ _ nonnull 或 _ _ nullable)

It refers to the third parameter (the block one).

The 文件 doesn't cover with examples how to specify the nullability of block parameters. It states verbatim

您可以立即使用非下划线的可空和非空表单 在开括号之后,只要类型是一个简单的对象或 block pointer.

我尝试把两个关键字之一的块(在任何位置)没有任何运气。还尝试了下划线前缀变体(__nonnull__nullable)。

因此,我的问题是: 如何为块参数指定空性语义?

75790 次浏览

看起来起作用了

- (void)methodWithArg:(nonnull NSString *)arg1
andArg:(nullable NSString *)arg2 completionHandler:(nullable void (^)
(NSArray * _Nullable results, NSError * _Nonnull error))completionHandler

您需要为块及其参数指定可为空性..。

编辑: 有关更多信息,请参见 Swift Blog 斯威夫特博客

下面是我在 NSerror * * 案例中使用的方法:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;

为了在头文件中定义完成,我这样做了

typedef void (^PublicEventsHandler) (BOOL success, NSArray * _Nullable publicEvents);

当然,我同意公认的答案。

摘自 apple 开发者博客: The Core: _ Nullable and _ Nonnull

可以使用非下划线形式 可空和非空的 immediately after an open parenthesis,只要 the type is a simple object or block pointer.

非下划线的窗体比下划线的窗体要好,但是 您仍然需要将它们应用到头部 中的每个类型。

你也可以这样做:

- (id __nullable)methodWithArg:(NSString * __nullable)arg1
andArg:(NSString * __nonnull)arg2
completionHandler:(void (^ __nonnull)(NSArray * __nonnull results, NSError * __nullable error))completionHandler;

这只取决于您更喜欢哪种语法。

根据 苹果博客(“ Nullability and Objective-C”), 你可以利用

NS_ASSUME_NONNULL_BEGINNS_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
  • 如果 错误NSError **类型,应该是 NSError * _Nullable * _Nullable
  • 如果对象是 id *类型,最好使用 id _Nullable * _Nonnull,它取决于(可能你想要一个 _Nullable id * _Nullable类型)。
  • 如果 object 是 NSObject *类型,则需要在指针后放置注释,如 NSObject * _Nullable * _Nonnull所示

注意

_Nonnull_Nullable应该在指针或 id之后使用(苹果在示例代码 AAPLListItem * _Nullable中这样做) ,但是非下划线的形式 nonnullnullable可以在开括号之后使用。

然而,在一般情况下,还有更好的方法来写这些吗 annotations: within method declarations you can use the 非下划线的表格 nullablenonnull在打开后立即显示 括号,只要该类型是一个简单的对象或块指针。

“ Nullability and Objective-C”查看更多信息

为了安全起见,这条规则有几个例外:

  • typedef类型通常不具有固有的可空性ーー它们可以 根据上下文的不同,很容易变为可空或不可空。 因此,不假定 typedef类型为 nonnull,即使在 审计地区。
  • More complex pointer types like id * must be 显式注释。例如,指定一个非空指针 对于可为空的对象引用,使用 _Nullable id * _Nonnull
  • 特定类型的 NSError **经常用于通过以下方式返回错误 method parameters that it is always assumed to be a nullable pointer 到一个可空的 NSError引用。

_Nullable id * _Nonnull可以混淆,对 id _Nullable * _Nonnull的理解更好。

_Nonnull and _Nullable should used after pointer or id (Apple does in the example code AAPLListItem * _Nullable)