我不认为我想做的事情是可能的,但是这里有些人比我自己更狡猾,所以我想我还是会问......
想象一下,我们有一个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中有一种方法可以知道谁在请求它吗?
添
答案 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
进行沟通。
然后创建一个具有C
和B
的班级A
。不要在其上实施任何东西。遵循alloc
和init
返回(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)
且两者都是对象,所以它是一个安全的隐式转换,并且编译器不会抱怨您继续在{{1}上调用方法那些没有实现。