子类中的窄类型属性

时间:2012-05-23 00:04:09

标签: objective-c ios

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

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

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

2 个答案:

答案 0 :(得分: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,因此没有设置器,也没有危险。

答案 1 :(得分:1)

如果AWImageView从UIImageView派生(子类),它是一个UIImageView,所以编译器都保持不变。

from the docs:

  

enter image description here

     

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