为什么此代码会生成以下警告?
@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
是否因为在第二种情况下我们从限制性更强到限制性更强?
答案 0 :(得分:4)
这完全是因为 Liskov substitution principle
根据这个原则:
如果S是T的子类型,那么对象是 类型T可以用类型S的对象替换而不改变任何类型 该计划的理想属性。
在您的示例中:Bar
是Foo
的子类型。因此,您应该能够将Foo
的实例替换为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不同)这些规则并不严格,您可以轻易欺骗编译器。