子类中的窄类型属性

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

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

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

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

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

例如,使用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实例setMyBvalue:为一个B实例,并且输入规则说你可以传递一个B,该方法需要一个C,然后就会出现混乱。

但是在你的情况下,你所覆盖的属性是readonly ,所以没有setter,也没有危险。

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

来自文档:

在此处输入链接说明http://sofzh.miximages.com/objective-c/graphichierarchy.gif
图1-1 […]这只是说Square类型的对象不仅是一个正方形,它还是一个矩形,一个形状,一个图形和一个NSObject类型的对象。