子类中的窄类型属性
今天我遇到了一个奇怪的行为,我没想到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类型的对象。