4

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

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

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

4

2 回答 2

5

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

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

例如,使用 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,因此没有设置器,也没有危险。

于 2012-05-23T04:44:22.080 回答
1

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

来自文档:

在此处输入图像描述

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

于 2012-05-23T00:05:43.210 回答