首页 > 解决方案 > 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

是因为在第二种情况下,我们从限制更多变为限制更少?

标签: objective-c

解决方案


这都是因为Liskov 替换原则

根据这个原则:

如果 S 是 T 的子类型,则 T 类型的对象可以被 S 类型的对象替换,而不会改变程序的任何所需属性。


在您的示例中:BarFoo. 所以你应该能够用 instance of 替换 instance Fooof Bar

换句话说,想象方法

- (void)doSomethingWith:(Foo *)object {
    [object m:nil];
}

如果你传递给这个方法实例Foo- 一切正常。但是您可能不会将实例传递给它Bar- 因为您可能不会调用[Bar m:nil]

在这里你可以看到,这段代码违反了 Liskov 替换原则。


否则,在第二个示例中,一切都很好。

想象方法:

- (void)doSomethingWith:(Foo *)object {
    [object m:@""]; // _Nonnull requirement
}

如您所见,您可以将FooBar类的实例传递给此方法。


注意:这里需要注意的是,在 Objc(与 Swift 不同)中,这些规则并不那么严格,您很容易欺骗编译器。


推荐阅读