我们可以确保 `+ (nonnull instancetype)sharedInstance;` 的可空性吗?
Can we ensure nullability of `+ (nonnull instancetype)sharedInstance;`?
这是一个关于如何在 NSObject
class.
中优雅地规避 init
的可空性的问题
所以这是一个 classic objective-c 实现:
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^
{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
但现在我想声明为nonnull
,如果可能的话:
+ (nonnull instancetype)sharedInstance;
不幸的是,init
returns 一个 nullable instancetype
值。我应该在调用 init
之后添加一个 NSAssert
还是什么?
我注意到有些人甚至 document nonnull
values as being in reality nullable
。这有意义吗?
我是否应该大胆地在任何地方简单地添加 NS_ASSUME_NONNULL_BEGIN
,而不真正确保值是 nonnull
?
这里好像有两个问题:
如何确保在我的单例 sharedInstance
方法中产生的值和由该方法 return 产生的值在 运行 时实际上不为零?
我如何满足可空性注释、编译器警告和 Swift 桥接我正在 return 一个 nonnull
指针的系统?
确保/执行nonnull
在某些时候,每个 API 合同都会分解为人类合同。编译器可以帮助确保,例如,您不能从 return 类型为 nonnull
的方法中获取 nullable
调用的结果和 return 它。 . 但通常某处有一个 return 类型为 nonnull
的原始调用,仅仅是因为编写它的程序员说,"I promise to never return null, cross my heart, etc."
如果您熟悉 Swift,这类似于隐式解包可选的情况——当您 "know" 一个值不能为 nil,但不能证明时,您可以使用它们该知识对编译器来说是因为该知识在源代码之外(例如,来自故事板或捆绑资源的东西)。
这就是这里的情况——你 "know" init
永远不会 return nil,要么是因为你写了/有相关初始化程序的源代码,要么是因为它只是 NSObject
的 init
记录到 return self
没有做任何事情。对该初始化程序的调用失败的唯一情况是因为前面的 alloc
调用失败(因此你在 nil
上调用一个方法,它总是 returns nil
).如果 alloc
是 return 零,你已经在 dire straits 并且你的过程对这个世界来说并不长 - 这不是设计 API 的失败案例左右。
(可空性注释通常用于描述 API 的预期用途,而不是更极端的边缘和角落情况。如果 API 调用仅因为 universal error将其注释为可为空没有意义;同样,如果 API 仅在可通过非空参数注释排除的输入上失败,则可以假定 return 值非空。)
所以,长话短说:是的,只需将 NS_ASSUME_NONNULL
放在 header 周围,然后按原样运送 sharedInstance
实施。
返回一个 nonnull
可为 null 的
这里不是这种情况,但假设您有一个注释为 nullable
的值,但您知道(或 "know")它永远不会为 nil 并且想要 return 它来自你的 nonnull
-注释方法。而且您遇到了尝试时收到编译器警告的情况。
有一个语法——只需将值转换为预期的 return 类型、注释和所有:
return (NSWhatever *_Nonnull)whatever;
在你的情况下,这不应该是必需的——因为你正在处理 id
和 instancetype
特殊类型,编译器对可空性转换更宽容,可能不会发出警告开始于.
这是一个关于如何在 NSObject
class.
init
的可空性的问题
所以这是一个 classic objective-c 实现:
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^
{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
但现在我想声明为nonnull
,如果可能的话:
+ (nonnull instancetype)sharedInstance;
不幸的是,init
returns 一个 nullable instancetype
值。我应该在调用 init
之后添加一个 NSAssert
还是什么?
我注意到有些人甚至 document nonnull
values as being in reality nullable
。这有意义吗?
我是否应该大胆地在任何地方简单地添加 NS_ASSUME_NONNULL_BEGIN
,而不真正确保值是 nonnull
?
这里好像有两个问题:
如何确保在我的单例
sharedInstance
方法中产生的值和由该方法 return 产生的值在 运行 时实际上不为零?我如何满足可空性注释、编译器警告和 Swift 桥接我正在 return 一个
nonnull
指针的系统?
确保/执行nonnull
在某些时候,每个 API 合同都会分解为人类合同。编译器可以帮助确保,例如,您不能从 return 类型为 nonnull
的方法中获取 nullable
调用的结果和 return 它。 . 但通常某处有一个 return 类型为 nonnull
的原始调用,仅仅是因为编写它的程序员说,"I promise to never return null, cross my heart, etc."
如果您熟悉 Swift,这类似于隐式解包可选的情况——当您 "know" 一个值不能为 nil,但不能证明时,您可以使用它们该知识对编译器来说是因为该知识在源代码之外(例如,来自故事板或捆绑资源的东西)。
这就是这里的情况——你 "know" init
永远不会 return nil,要么是因为你写了/有相关初始化程序的源代码,要么是因为它只是 NSObject
的 init
记录到 return self
没有做任何事情。对该初始化程序的调用失败的唯一情况是因为前面的 alloc
调用失败(因此你在 nil
上调用一个方法,它总是 returns nil
).如果 alloc
是 return 零,你已经在 dire straits 并且你的过程对这个世界来说并不长 - 这不是设计 API 的失败案例左右。
(可空性注释通常用于描述 API 的预期用途,而不是更极端的边缘和角落情况。如果 API 调用仅因为 universal error将其注释为可为空没有意义;同样,如果 API 仅在可通过非空参数注释排除的输入上失败,则可以假定 return 值非空。)
所以,长话短说:是的,只需将 NS_ASSUME_NONNULL
放在 header 周围,然后按原样运送 sharedInstance
实施。
返回一个 nonnull
可为 null 的
这里不是这种情况,但假设您有一个注释为 nullable
的值,但您知道(或 "know")它永远不会为 nil 并且想要 return 它来自你的 nonnull
-注释方法。而且您遇到了尝试时收到编译器警告的情况。
有一个语法——只需将值转换为预期的 return 类型、注释和所有:
return (NSWhatever *_Nonnull)whatever;
在你的情况下,这不应该是必需的——因为你正在处理 id
和 instancetype
特殊类型,编译器对可空性转换更宽容,可能不会发出警告开始于.