这可能是Java编码员报告的一个常见的Objective-C问题,但我不知道该怎么称呼它或如何搜索答案。假设我有一个类和另一个扩展它的类:
AbstractModel
@interface AbstractModel {
}
ModelImpl
@interface ModelImpl : AbstractModel {
}
除了这些之外,我还有两个类,另一个扩展另一个类:
ControllerA
@interface ControllerA {
AbstractModel *foo;
}
@property (nonatomic, retain) AbstractModel *foo;
ControllerB
@interface ControllerB : ControllerA {
}
我希望能够说ControllerA中的foo
可以包含AbstractModel或其任何子类型。但是,如果我尝试在其中存储除AbstractModel之外的任何内容,编译器会给出警告。 (当然我理解,在ObjC中,类不能真的是抽象的,而是怜悯我。)
我还希望能够“锁定”特定子类中的foo
属性。我想说,ControllerB中的foo
只能包含一个ModelImpl4。这可能吗?
解决此类问题的常规Objective-C最佳实践是什么?以这种方式使用继承 - 或者实现这个目标 - 在Objective-C中不是一个好主意吗?
答案 0 :(得分:3)
首先,我想理解这一点:
然而,编译器给了我一个 如果我试图存储任何东西警告 除了它中的AbstractModel。
这没有意义。您应该能够毫无困难地将AbstractModel
的子类分配给foo
。你看到了什么问题?
接下来,你所描述的并不是重写,而是超载。您正在尝试更改方法的返回类型,而您无法在ObjC中执行此操作。这个问题有很好的解决方案,但在某种程度上取决于你的真正目标。
首先,您可以摆脱-foo
中的ControllerA
。如果ControllerA
实际上是抽象的,那么最好不要有一个。如果ControllerA
是抽象的,我绝对建议你摆脱该层的foo
ivar。你应该将ivars放在子类中。
或者,您可以将类型化方法添加到子类中。例如,ControllerB
除了继承的-modelBFoo
之外还有-foo
方法。这些方法是相同的;他们会有不同的回报类型,允许在所有来电者中打字。
不要忽略警告。他们在那里保护你(在ObjC,他们是你必须保护你的全部)。尽可能限制你的类型转换。他们将编译器错误(好)转移到运行时异常(坏)。
答案 1 :(得分:1)
是。解决第一个问题的最简单方法就是忽略编译器警告。它将在运行时工作。如果您不喜欢这些警告,可以进行类型转换:
foo = (AbstractModel *)thisIsAModelImpl;
然后,要为ControllerB
“锁定”,您只需将此行添加到.h文件中
ModelImpl *foo;
并且,您希望覆盖(重新定义)foo
中处理ControllerB
的任何方法。
编辑:为了清楚起见,这就是我所说的重写。
如果你有方法(在ControllerA
)
-setFoo:(AbstractModel *)newModel;
-(AbstractModel *)foo;
您可以将这些行更改为(ControllerB
)
-setFoo:(ModelImpl*)newModel;
-(ModelImpl*)foo;