16
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

method_exchangeImplementationsでクラスメソッドを置換する

Last updated at Posted at 2012-08-29

Objective-Cでクラスメソッドを置換するやり方について忘れがちなのでメモ
テストコードを書いてるときなどに、テスト対象のコードの中で呼んでいるクラスメソッドをモックに差し替えたい場合があります。
本来であればその手の依存性はうまい事排除してあげるのが良いのですが、いかんともしがたい場合ですね。

Objective-Cはruntimeに触る事が出来るので割りとサクッとできます。
以下のクラスのメソッドを入れ替えてみましょう。


@interface GlobalClass : NSObject

+ (BOOL)classMethod;

@end

適当なカテゴリで入れ替えたいメソッドと同じ定義のクラスメソッドをそのクラスに生やします。


#import <objc/runtime.h>

@interface SomelClass(TestCode)

+ (BOOL)replacing_classMethod;

@end

@implementation SomeClass(TestCode)

+ (BOOL)replacing_classMethod {
    // iroiro suruyo
}

@end

method_exchangeImplementationsで実装を入れ替えてあげます。
メソッドを入れ替えるコードはこちら


@interface SomeTestClass : GHTestCase {
    Method oldMethod;
    Method newMethod;
}

@end

@implementation SomeTestClass

- (void)setUp {
    oldMethod = class_getClassMethod([SomeClass class], @selector(classMethod));
    newMethod = class_getClassMethod([SomeClass class], @selector(replacing_classMethod));
    method_exchangeImplementations(oldMethod, newMethod);
}

@end

これで入れ替え完了です。

method_exchangeImplementationsで何が起こっているか、前後で値を見てみると、implementationの指す先が変わっているのがわかります。

Method oldMethod = class_getClassMethod([SomeClass class], @selector(classMethod));
Method newMethod = class_getClassMethod([SomeClass class], @selector(replacing_classMethod));
NSLog(@"oldMethod name is %@, imp is %x", NSStringFromSelector(method_getName(oldMethod)), (NSInteger)method_getImplementation(oldMethod));
NSLog(@"newMethod name is %@, imp is %x", NSStringFromSelector(method_getName(newMethod)), (NSInteger)method_getImplementation(newMethod));

method_exchangeImplementations(oldMethod, newMethod);

NSLog(@"oldMethod name is %@, imp is %x", NSStringFromSelector(method_getName(oldMethod)), (NSInteger)method_getImplementation(oldMethod));
NSLog(@"newMethod name is %@, imp is %x", NSStringFromSelector(method_getName(newMethod)), (NSInteger)method_getImplementation(newMethod)); 

oldMethod name is classMethod, imp is 375d9
newMethod name is replacing_classMethod, imp is 375f5
oldMethod name is classMethod, imp is 375f5
newMethod name is replacing_classMethod, imp is 375d9

以上です。
黒魔法は用法用量を守って楽しく使おう

16
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?