我有一个A类.B继承A.两个类都实现了method1和method2。
A中的method1调用method2。它看起来像......
- (void)method1{
// some code
[self method2];
// some code
}
- (void)method2{
// some work
}
B中的method1调用超类方法1,B也覆盖方法2。
- (void)method1{
[super method1];
}
- (void)method2{
// some work
}
现在,当B的实例被创建并调用method1时,方法1调用B中的method2。我想要做的是从A的方法1调用A的方法2,即使是从子(B)调用它。
换句话说,在A的方法1中,我想“强制”在同一所有者(类)中调用该方法。 有没有简单的方法呢?我想我可以通过调用objective-c运行时函数来实现它,但我想知道是否有更简单的方法。
我知道这不是我们在通常情况下应该做的设计,但是从一个复杂的原因我必须这样做。所以请不要建议我改变设计或问我该计划的最初目标是什么。
答案 0 :(得分:0)
作为我能提出的最简单的解决方案,请使用BOOL
标志来决定method2
的行为方式:
@interface B ()
@property (nonatomic) BOOL shouldCallSuperMethod2;
@end
@implementation B
- (void)method1{
self.shouldCallSuperMethod2 = YES;
[super method1];
self.shouldCallSuperMethod2 = NO;
}
- (void)method2{
if (self.shouldCallSuperMethod2) {
[super method2];
}
else {
// some work
}
}
@end
请注意,此解决方案不是线程安全的。
UPD 另一种有趣的方式,使用运行时魔术:
@import ObjectiveC.runtime;
@implementation B
- (void)method2 {
NSUInteger returnAddress = (NSUInteger)__builtin_return_address(0);
NSUInteger callerIMPAddress = 0;
SEL interestingSelector = @selector(method1);
// Iterate over the class and all superclasses
Class currentClass = object_getClass(self);
while (currentClass)
{
// Iterate over all instance methods for this class
unsigned int methodCount;
Method *methodList = class_copyMethodList(currentClass, &methodCount);
unsigned int i;
for (i = 0; i < methodCount; i++)
{
// Ignore methods with different selectors
if (method_getName(methodList[i]) != interestingSelector)
{
continue;
}
// If this address is closer, use it instead
NSUInteger address = (NSUInteger)method_getImplementation(methodList[i]);
if (address < returnAddress && address > callerIMPAddress)
{
callerIMPAddress = address;
}
}
free(methodList);
currentClass = class_getSuperclass(currentClass);
}
if (callerIMPAddress == (NSUInteger)[self methodForSelector:interestingSelector]) {
// method2 is called from method1, call super instead
[super method2];
}
else {
// some work
}
}
@end
可以找到识别来电者的其他有趣方法in answers to this question