0

我不认为我想做的事情是可能的,但是这里有比我更狡猾的人,所以我想我还是问一下……

假设我们有一个 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 的版本。有什么建议么?例如,在我的吸气剂中,有没有办法知道谁在请求它?

蒂姆

4

3 回答 3

0

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

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

(顺便说一句,如果你需要这样的行为,你的班级可能设计得很糟糕......)

于 2012-06-13T19:35:50.537 回答
0

嗯,很好地覆盖 B 中的属性意味着 B 中的任何访问器都将访问 B 中的新属性。A 的行为保持不变,A 中的访问器将始终访问 A 中的原始属性。A 类不能也不应该知道它的子类。

如果您希望子类继续访问超类属性,则不能覆盖它。时期。

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

最后,假设您将 A、B 甚至 C 类型的类放在一个包中,然后忘记它们的类型,只知道它们共享一个 is-a 关系,然后您可以使用动态绑定/自省来决定将调用哪个类的方法基于它的类型。

于 2012-06-13T19:46:04.187 回答
0

你可以在技术上实现你想要的,但是在一个可怕的迂回黑客攻击中。将这类事情放入您的生产代码中,后果自负,如果这一切都崩溃了,不要指望任何同情。

不要创建B的子类A,仅将其作为具有A. 实现那些B你本来会在子类中替换的方法。对于处理items,请确保对B'setItems:进行适当的相应调用A- 确实为您覆盖但您希望也与A.

然后创建一个C具有 aB和a 的类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

现在每个引用A都是对self实例A而不是子类的引用。尽管如此,您B在系统中有一个 的实例,它会A通过获取相关实例A优先服务的任何消息来表现它的继承,同时能够将它想要的任何内容推迟到A.

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

于 2012-07-20T02:27:24.063 回答