【问题标题】:Narrow type of property in subclass子类中的窄属性类型
【发布时间】:2012-05-23 00:04:08
【问题描述】:

今天我遇到了一个我没想到 Objective-C 编译器会允许的奇怪行为。

在 UITableViewCell 中,有一个 UIImageView 类型的名为 imageView 的属性。我继承了 UITableViewCell 并覆盖了 imageView,除了我将它设为 AWImageView 类型,其中 AWImageView 是 UIImageView 的子类。我以为它不会编译,但确实如此。一切正常。我对这种行为感到非常震惊。

是否正式允许缩小子类中的属性类型?或者这是 Objective-C 编译器中的一个错误使它工作?

【问题讨论】:

    标签: objective-c ios


    【解决方案1】:

    您对被允许这样做的怀疑是有根据的,但在这种特殊情况下,您还可以...

    在对重写的严格子类型解释中,重写方法可以接受更通用类型的参数并返回更具体类型的值。

    例如,使用 Objective-C,给定:

    @interface A : NSObject { ... }
    @interface B : A { ... }
    @interface C : B { ... }
    

    和B中的方法M:

    - (B *) M:(B *)arg { ... }
    

    然后在严格的子类型下的 C 类中,这可以在 C 类中使用:

    - (C *) M:(A *)arg { ... }
    

    这是安全的,因为如果你有一个明显 B 对象的引用:

    B *bObj = ...;
    

    然后调用方法M:

    B *anotherBObj = [bObj M:[B new]];
    

    那么无论bObj实际上是B还是C,调用的类型都是正确的——如果它是一个C对象,那么参数是B就可以了,因为它也是A,结果是C就可以了它也是一个B。

    这将我们带到,不完全,您的财产;在 Objective-C 中,属性只是两种方法的简写:

    @property B *myBvalue;
    

    是以下的简写:

    - (void) setMyBvalue:(B *)value;
    - (B *) myBvalue;
    

    如果该属性在 B 中声明,并且您在 C 类中使用 C 值属性覆盖它:

    @property C *myBvalue;
    

    你得到:

    - (void) setMyBvalue:(C *)value;
    - (C *) myBvalue;
    

    并且setMyBvalue: 方法违反了严格的子类型化规则 - 将 C 实例强制转换为 B 实例,并且类型化规则说您可以传递 B,该方法需要一个 C,然后就会出现混乱。

    但是在您的情况下,您要覆盖的属性是 readonly,因此没有设置器,也没有危险。

    【讨论】:

      【解决方案2】:

      如果 AWImageView 从 UIImageView 派生(子类),它是一个 UIImageView,所以对于编译器来说都是一样的。

      from the docs:

      图 1-1 […] 这只是说 Square 类型的对象不仅是正方形,它还是矩形、形状、图形和 NSObject 类型的对象。

      【讨论】:

      • 你知道有什么文件可以支持吗?我很确定 Objective-C 之前不允许这样做。 -(id)init 返回 id 因为它不允许子类覆盖方法并返回更窄的类型。
      • 这在任何支持继承的基于类的面向对象语言中都是非常正常的行为。子类可以被视为父类。而你在初始化时弄错了:它指定了 id,因此任何子类都可以返回自己的对象(或 [参见类集群] 另一个类,其行为类似)。
      • 文档中的好引述,但只是想指出您引述中的图像是死链接。
      猜你喜欢
      • 1970-01-01
      • 2021-03-13
      • 2018-04-23
      • 1970-01-01
      • 2017-01-13
      • 1970-01-01
      • 1970-01-01
      • 2020-09-16
      • 2021-11-05
      相关资源
      最近更新 更多