2

假设我有两个 Objective-c 类,LBFoo并且LBBar.

LBFoo我有一个看起来像这样的方法:

- (void)doSomethingWithFoo:(NSNumber*)anArgument
{
  if(anArgument.intValue > 2)
    [LBBar doSomethingWithLBBar];
  else
    [LBBar doSomethingElseWithLBBar];
}

相反,我想做的是传递一个LBBar没有提前声明的实现。(如在动态覆盖现有的@selector 中LBBar

我知道IMP存在一个类型,是否可以将一个传递IMP给一个类以更改其选择器实现。

4

2 回答 2

2

您可以在Objective-C 运行时method_setImplementation(Method method, IMP imp)使用该函数。

如果你想设置一个实例方法,它会像这样工作

method_setImplementation(class_getInstanceMethod([yourClass class], @selector(yourMethod)), yourIMP);

如果你想要一个类方法,只需使用class_getClassMethod而不是class_getInstanceMethod. 论据应该相同。

这里的所有都是它的。请注意,IMP 只是一个 void 函数指针,前 2 个参数是id selfSEL _cmd

于 2012-07-31T18:28:57.707 回答
1

您当然可以使用运行时函数来做这样的事情,* 但我建议这正是引入Blocks来解决的问题。它们允许你传递一大块可执行代码——你的方法实际上可以接受一个 Block 作为参数并运行它。

这是一个SSCCE:

#import <Foundation/Foundation.h>

typedef dispatch_block_t GenericBlock;

@interface Albatross : NSObject 
- (void)slapFace:(NSNumber *)n usingFish:(GenericBlock)block;
@end

@implementation Albatross

- (void)slapFace:(NSNumber *)n usingFish:(GenericBlock)block
{
    if( [n intValue] > 2 ){
        NSLog(@"Cabbage crates coming over the briny!");
    }
    else {
        block();    // Execute the block
    }
}

@end

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        Albatross * p = [Albatross new];
        [p slapFace:[NSNumber numberWithInt:3] usingFish:^{
            NSLog(@"We'd like to see the dog kennels, please.");
        }];
         [p slapFace:[NSNumber numberWithInt:1] usingFish:^{
            NSLog(@"Lemon curry?");
        }];

    }
    return 0;
}

*请注意,使用method_setImplementation()将更改以后每次从任何地方调用该方法时使用的代码——这是一个持久的更改。

于 2012-07-31T18:53:28.050 回答