2012-07-31 87 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