这是一个关于如何优雅地规避init
课程中NSObject
的可空性的问题。
所以这是一个经典的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
会返回nullable instancetype
值。我应该在致电NSAssert
之后添加init
或其他内容吗?
我注意到有些人甚至document nonnull
values as being in reality nullable
。这有意义吗?
我应该大胆一点,只需在任何地方添加NS_ASSUME_NONNULL_BEGIN
,而不是真正确保价值为nonnull
?
答案 0 :(得分:5)
这里似乎有两个问题:
如何确保在我的单例sharedInstance
方法中生成并由该方法返回的值在运行时实际上不是零?
如何满足nullabilty注释,编译器警告和Swift桥接系统我正在返回nonnull
指针?
nonnull
在某些时候,每个API合同都会分解为人工合同。编译器可以帮助确保,例如,您无法获取nullable
调用的结果并从返回类型为nonnull
的方法返回...但某处通常会有原始调用其返回类型为nonnull
,仅仅是因为编写它的程序员说:“我保证永远不会返回null,交叉我的心等等。”
如果您熟悉Swift,这与Implicitly Unwrapped Optionals的情况类似 - 当您“知道”某个值不能为零时使用这些,但无法向编译器证明该知识,因为该知识在源代码的外部(例如来自故事板或捆绑资源的东西)。
这就是这里的情况 - 你“知道”init
将永远不会返回nil,因为你为有问题的初始化程序编写/拥有源代码,或者因为它只是NSObject
的{{1}}在没有做任何事情的情况下记录到init
。调用该初始值设定项失败的唯一情况是因为前面的return self
调用失败(因此您在alloc
上调用方法,该方法始终返回nil
)。如果nil
返回nil,那么您已经在dire straits,并且您的流程对于这个世界而言并不长 - 这不是设计API的失败案例。
(Nullability注释通常用于描述API的预期用途,而不是更极端的边缘和边角情况。如果API调用仅因universal error而失败,则将其注释为可空是没有意义的;同样,如果API仅对可通过非空参数注释排除的输入失败,则可以假定返回值为非空。)
所以,长话短说:是的,只需将alloc
放在标题周围,然后按原样发送NS_ASSUME_NONNULL
实现。
sharedInstance
可以为空的这不是这种情况,但假设你有一个注释为nonnull
的值,但是你知道(或“知道”)它永远不会是零并想要从{{1}返回它 - 注释方法。并且您处于编译器警告状态的情况下。
有一种语法 - 只需将值转换为预期的返回类型,注释和所有:
nullable
在你的情况下,这不应该是需要的 - 因为你正在处理nonnull
和return (NSWhatever *_Nonnull)whatever;
特殊类型,编译器对于可空性转换更加宽容,并且可能不会警告开始