2015-11-03 62 views
1

我有一个类A.B继承A.这两个类都实现了method1和method2。 A调用方法2中的方法1。它看起来像...当从子女调用时调用原始类方法

- (void)method1{ 
    // some code 
    [self method2]; 
    // some code 
} 

- (void)method2{ 
    // some work 
} 

B中的method1调用超类方法1,B也覆盖method2。

- (void)method1{ 
    [super method1]; 
} 

- (void)method2{ 
    // some work 
} 

现在,当B的实例被创建和被称为方法1 A的方法1调用B.方法2.我想要做的是从调用A的方法1 A的方法2,即使它是从子(B)叫什么。

换句话说,在A的method1中,我想“强制”地调用同一个所有者(类)中的方法。 有没有简单的方法来做到这一点?我想我可以通过调用objective-c运行时函数来实现,但我想知道是否有更简单的方法。

我知道这不是我们通常应该做的设计,但是从一个复杂的理由我必须这样做。所以请不要提出改变设计或问我该计划的最初目标是什么。

+0

我不认为你可以。调度表将负责在运行时解析正确的方法,并且由于类型是B和B有一个方法将被调用的method2的重写版本。也许通过方法swisseling这可以完成。 –

+0

您可以通过临时将您的实例切换到A类来实现。但是不要那样做。 – Avi

+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