代码之家  ›  专栏  ›  技术社区  ›  Antonio

Objective-C使用非Null参数重写\u Nullable参数

  •  6
  • Antonio  · 技术社区  · 6 年前

    为什么此代码会生成以下警告?

    @interface Foo : NSObject 
    - (void)m:(id _Nullable)p;
    @end
    
    @interface Bar : Foo
    - (void)m:(id _Nonnull)p;
    @end
    

    参数类型上存在冲突的nullability说明符,“\u Nonnull”与现有说明符“\u Nullable”[-Wnullability]

    但另一种方式不会生成警告:

    @interface Foo : NSObject 
    - (void)m:(id _Nonnull)p;
    @end
    
    @interface Bar : Foo
    - (void)m:(id _Nullable)p;
    @end
    

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

    1 回复  |  直到 6 年前
        1
  •  5
  •   Anton Belousov    5 年前

    都是因为 Liskov substitution principle

    根据这一原则:

    如果S是T的子类型,则 类型T可以替换为类型S的对象,而不改变 程序的理想特性。


    在您的示例中: Bar 是的子类型 Foo 。因此,您应该能够替换 Foo公司 具有的实例 酒吧

    换句话说,想象方法

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

    如果传递到此方法实例 Foo公司 -一切都很好。但您不能将以下实例传递给it 酒吧 -因为你可能不会打电话 [Bar m:nil]

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


    否则,在第二个示例中,一切正常。

    想象方法:

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

    如您所见,您可以将这两个 Foo公司 酒吧 课程。


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