LoginSignup
17
14

More than 5 years have passed since last update.

swizzlingを理解する

Posted at

objective-cではオブジェクトへメッセージが送られたときに呼び出されるメソッドは実行時に
決定する(動的結合)。この性質を使ってメッセージとして送られてきたセレクタによって
解決されるメソッドを入れ替えてしまう方法が存在する。これをswizzlingと呼ぶ。

やり方は凄く簡単でFooクラスのhogeメソッドとbarメソッドを置き換えるとすると
まずは両方のメソッド情報をclass_getInstanceMethodを使用して取得。
Method hoge_method = class_getInstanceMethod([Foo class], @selector(hoge));
Method bar_method = class_getInstanceMethod([Foo class], @selector(bar));
交換するにはmethod_exchangeImplementationsを実行するだけ。
method_exchangeImplementations(hoge_method, bar_method);

class_getInstanceMethodとmethod_exchangeImplementationsはランタイムAPIとして
提供されている。ランタイムの提供している関数を呼び出すことでswizzlingなどのように
一見変わったごにょごにょしたことが出来たりする。
ランタイムAPI

参考までに検証に用いたコードを以下に示す。

main.m
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface Foo : NSObject
-(void)hoge;
-(void)bar;
@end

@implementation Foo
-(void)hoge
{
    NSLog(@"selector:%@  method:hoge method!!",NSStringFromSelector(_cmd));
}
-(void)bar
{
    NSLog(@"selector:%@ method:bar method!!",NSStringFromSelector(_cmd));
}
@end

int main()
{
    Foo *foo =[[Foo alloc] init];
    //それぞれのメソッドを呼び出す。
    [foo hoge];
    [foo bar];

    Method hoge_method = class_getInstanceMethod([Foo class], @selector(hoge));
    Method bar_method = class_getInstanceMethod([Foo class], @selector(bar));

    method_exchangeImplementations(hoge_method, bar_method);

    //swizzlingでメソッドを交換後にそれぞれ呼び出し。
    [foo hoge];
    [foo bar];

    return 0;
}

どういう時に使うのか少し調べてみると、
ソースが公開されてないメソッドの動きを解析するときに独自メソッドに
置き換えて色々情報を取得するとか、
参考)Estimote Beacon をリバースエンジニアリング
http://d.hatena.ne.jp/shu223/20140131/1391155397

Effective-Objective-C2.0でもソースコードを持たないメソッドのデバッグで使えと
書いてあり、実用的に使うよりもデバッグ、解析用途が多いのかなという印象。

実用的な例としては、以下のような記事もあった。
http://qiita.com/shu223/items/3868894458832d4cc8e1
実用的に使う場合もあるみたい。

17
14
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
17
14