覆盖基类@property,同时仍然允许基类访问它

时间:2012-06-13 19:21:10

标签: objective-c oop

我不认为我想做的事情是可能的,但是这里有些人比我自己更狡猾,所以我想我还是会问......

想象一下,我们有一个A类:

@interface A
@property (strong) NSArray *items;
// There'll be methods and stuff too
@end

现在,我们需要放弃替代这个类来改变一些行为方面:

@interface B : A
@property (strong) NSArray *items;
// There'll be methods and stuff too
@end

特别是,我们覆盖“items”属性,因为我们需要它来返回不同的东西。

这种方法很有效,直到调用B实例的方法(在A中实现而未被B重写)尝试访问“self.items”。它不是访问它自己的副本,而是访问B的重写版本,从而看到意想不到的结果 - 实际上在我的实际案例中崩溃了应用程序:(

我可以通过重命名B中的属性来解决这个问题 - 但是这不再是替代品,这是一种耻辱。

请注意,B类可以通过super访问A版本的属性。理想情况下,对A类房产的任何访问也可以访问A的版本。有什么建议?例如,在我的getter中有一种方法可以知道谁在请求它吗?

3 个答案:

答案 0 :(得分:0)

你的问题很混乱,但无论如何......

覆盖方法/属性不会全局更改它;它仅对执行覆盖的类进行更改。如果A的实例访问该属性,它仍将访问其自己的属性,它将不会被子类的实现神奇地接管。

(顺便说一下,如果您需要这样的行为,请允许我提一下您的课程设计可能非常糟糕......)

答案 1 :(得分:0)

嗯,完全覆盖B中的属性意味着B中的任何访问器都将访问B中的新属性.A的行为保持不变,A中的访问器将始终访问A中的原始属性。类不能也不应该从来没有意识到它的子类。

如果希望子类继续访问超类属性,则无法覆盖它。周期。

另请注意,必须在接口中声明属性(或其访问器)(基本上使其公开),才能在子类中直接访问其副本。这是必要的,因为在Objective-C中没有“受保护的属性”这样的东西。

最后让我们说你把类型A,B甚至C的类放在一个包中然后忘记它们的类型,只要知道所有共享一个is-a关系,那么你可以使用动态绑定/内省来决定哪个类的方法将根据它的类型进行调用。

答案 2 :(得分:0)

你可以在技术上实现你想要的,但是在一个可怕的回合中 - 关于黑客攻击。把这类东西放在你的生产代码中是你自己的危险,如果一切都崩溃了,不要期待任何同情。

不要让B成为A的子类,只使其成为具有A的类。在B上实现那些你原本会在子类中替换的方法。要处理items,请确保B setItems:A进行适当的相应调用 - 事实上,对于您覆盖的所有方法,您希望与A进行沟通。

然后创建一个具有CB的班级A。不要在其上实施任何东西。遵循allocinit返回(id)的常规约定,执行稍微奇怪的任务:

A *instance = [[C alloc] init];

C上只实现您首选的转发逻辑:

@implementation C

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if([self.instanceOfB respondsToSelector:aSelector]) return self.instanceOfB;
    return self.instanceOfA.
}

@end

现在每个引用Aself的引用都是对A实例的引用,而不是对子类的引用。不过你在系统中有一个B的实例,它会像A那样通过获取A的相关实例优先服务的任何消息来继承,能够将任何想要的东西推迟到A

通过为那些具有A实例C实例的类提供,他们将通过您的唯一继承逻辑而不是默认的东西。此外,因为您已在适当的位置返回(id)且两者都是对象,所以它是一个安全的隐式转换,并且编译器不会抱怨您继续在{{1}上调用方法那些没有实现。