objective-c - Objective-C 用 _Nonnull 参数覆盖 _Nullable 参数
问题描述
为什么此代码会生成以下警告?
@interface Foo : NSObject
- (void)m:(id _Nullable)p;
@end
@interface Bar : Foo
- (void)m:(id _Nonnull)p;
@end
参数类型上的可空性说明符冲突,“_Nonnull”与现有说明符“_Nullable”冲突 [-Wnullability]
但另一种方式不会产生警告:
@interface Foo : NSObject
- (void)m:(id _Nonnull)p;
@end
@interface Bar : Foo
- (void)m:(id _Nullable)p;
@end
是因为在第二种情况下,我们从限制更多变为限制更少?
解决方案
这都是因为Liskov 替换原则
根据这个原则:
如果 S 是 T 的子类型,则 T 类型的对象可以被 S 类型的对象替换,而不会改变程序的任何所需属性。
在您的示例中:Bar
是Foo
. 所以你应该能够用 instance of 替换 instance Foo
of Bar
。
换句话说,想象方法
- (void)doSomethingWith:(Foo *)object {
[object m:nil];
}
如果你传递给这个方法实例Foo
- 一切正常。但是您可能不会将实例传递给它Bar
- 因为您可能不会调用[Bar m:nil]
在这里你可以看到,这段代码违反了 Liskov 替换原则。
否则,在第二个示例中,一切都很好。
想象方法:
- (void)doSomethingWith:(Foo *)object {
[object m:@""]; // _Nonnull requirement
}
如您所见,您可以将Foo
和Bar
类的实例传递给此方法。
注意:这里需要注意的是,在 Objc(与 Swift 不同)中,这些规则并不那么严格,您很容易欺骗编译器。
推荐阅读
- reactjs - 设置状态时 react-google-recaptcha 重新渲染
- python - Visual Studio Code 在使用数据查看器时出错:“查看数据需要 Python 包‘熊猫’”
- flutter - 在为 Android 运行颤振应用程序时出现此异常
- javascript - 为带有文件夹的网站制作通用页眉和页脚
- flutter - 在 MaterialApp builder 属性中返回多个小部件
- sql - 多部分的 INNER JOIN (select ) 问题中的 CROSS JOIN DATA
- python - python 程序,如果使用了,想打印 5 次尝试
- python - vs代码上的pygame中的“没有可用的视频设备”错误
- ceph - ceph 中列出对象的工作原理
- c++ - 如何计算精确的时差(C++)?