2

私が2つのObjective-cクラスを持っていると仮定LBFooLBBarます。

私はLBFoo次のようなメソッドを持っています:

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

代わりに私がやりたいのは、LBBar事前に宣言されていない実装を渡すことです。(のように、内の既存の@selectorを動的にオーバーライドしますLBBar

型が存在することは知っていますが、セレクターの実装を変更するためにクラスにIMPを渡すことは可能ですか。IMP

4

2 に答える 2

2

method_setImplementation(Method method, IMP imp)この関数は、objective-cランタイムで使用できます。

インスタンスメソッドを設定する場合は、次のように機能します

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

クラスメソッドが必要な場合は、のclass_getClassMethod代わりに使用してclass_getInstanceMethodください。引数は同じである必要があります。

それがすべてです。id selfIMPは、最初の2つのパラメーターがとである単なるvoid関数ポインターであることに注意してください。SEL _cmd

于 2012-07-31T18:28:57.707 に答える
1

確かにランタイム関数を使用してこのようなことを行うことができます*が、これはまさにブロックが解決するために導入された種類の問題であることをお勧めします。実行可能コードのチャンクを渡すことができます。メソッドは実際にブロックを引数として受け入れて実行できます。

これが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 に答える