今天我遇到了一个奇怪的行为,我没想到Objective-C编译器会允许。
在UITableViewCell中,有一个名为imageView的属性为UIImageView。我将UITableViewCell子类化,并覆盖了imageView,除了我的AWImageView类型,其中AWImageView是UIImageView的子类。我认为它不会编译,但确实如此。一切正常。我对这种行为感到非常震惊。
正在缩小正式允许的子类中的属性类型吗?或者这是Objective-C编译器中的一个错误,它使它工作?
答案 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,所以编译器都保持不变。
图1-1 [...]这只是说Square类型的对象不仅是一个正方形,它还是一个矩形,一个形状,一个图形和一个NSObject类型的对象。