2012-07-31 46 views
2

假设我有两个客观c类,LBFooLBBar传入自定义选择器实现

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

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

我想这样做反而是通过一个实现,这不是宣布提前LBBar。 (如在动态覆盖LBBar中的现有@selector)

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

回答

2

你可以使用函数objective-c runtime

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

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

如果你想要一个类的方法,只是使用class_getClassMethod,而不是class_getInstanceMethod。争论应该是一样的。

这就是它的全部。需要注意的是IMP只是一个空函数指针与第2个参数为id selfSEL _cmd

+0

令人难以置信的有用。谢谢。 – 2012-07-31 18:57:03

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()将更改用于每一个方法是在未来从任何地方调用时的代码 - 这是一个持久的变化。

+0

感谢这个乔希,我实际上打算让这个变化永久化。通过动态方法生成执行一些元编程。 – 2012-07-31 18:56:35

+3

你应该看看[“消息”](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html%23//apple_ref/doc/uid/ TP40008048-CH104),“动态方法分辨率”和“消息转发”章节中的“ObjC运行时编程指南”。无论如何,你可能最终会使用'method_setImplementation()',但是对'NSObject'内置的动态消息处理有一些更高级的支持。 – 2012-07-31 19:04:04