7
7

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.

[Objective-C] Swizzling(ランタイムAPI)を使ってDebugをしやすくする

Last updated at Posted at 2014-03-17

最近、Effective Objective-C 2.0を読んでいます。
色々オススメされる書籍を読めば読むほど、C言語について理解する必要があるなーと思わされます。

今回は、Swizzlingを使ったDebug方法です。
アスペクト指向とか、そのあたりがキーワードですね。
JavaScriptでも比較的簡単に実装することが出来ますが、Objective-Cでもランタイムを使うことによって実装が可能です。

ざっくり手順。

  1. とある実装(メソッド)を置き換えるメソッドを準備する
  2. 実行時(ランタイム)にメソッドを入れ替える
  3. 置き換えるメソッド内で元々のメソッドも実行する
  4. NSStringなどの中が分からないメソッドに対しても機能拡張できる(ログ出力とか)

ということで、実際にNSStringlowwercaseStringメソッドにログ出力機能を付けるサンプルです。

##置き換える実装を準備する

置き換える実装(メソッド)の準備はカテゴリを使います。

@interface NSString (sample)

- (NSString *)swapLowercaseString;

@end

////////////////////////////////////////

@implementation NSString (sample)

- (NSString *)swapLowercaseString
{
	NSString *lowercase = [self swapLowercaseString];
	NSLog(@"Called. %@", lowercase);
	return lowercase;
}

@end

###差し替え部分

ここが要の部分ですね。
objc/runtime.hが必要です。
見た通り、ランタイム用の関数が定義されています。

main.m
#import <objc/runtime.h>
#import "NSString+sample.h"

int main(int argc, char * argv[])
{
	// NSString#lowercaseStringの実装を取り出す
	Method lowercaseString     = class_getInstanceMethod([NSString class], @selector(lowercaseString));

	// カテゴリで追加した`swapLowercaseString`の実装を取り出す
	Method swapLowercaseString = class_getInstanceMethod([NSString class], @selector(swapLowercaseString));

	// 取り出した実装を入れ替える
	method_exchangeImplementations(lowercaseString, swapLowercaseString);

	@autoreleasepool {
		return UIApplicationMain(argc, argv, nil, NSStringFromClass([SampleAppDelegate class]));
	}
}

###使用部分

NSString *sample1 = @"This is Sample";
NSString *sample2 = [sample1 lowercaseString]; // => "Called. this is sample"

NSLog(@"%@", sample2); // => "this is sample"

##簡単に解説

セレクタという名前から想像するに、なにかを選択しているわけですが、なにを選択しているかというと「実装を選択」しているわけです。
だから「セレクタ」っていうわけですね。

Objective-Cはコンパイル後にはCとして動作します。
当然、Cにはクラスという概念がありません。(オブジェクト指向言語ではない)
なので、ランタイムはObjecitve-Cで定義したインスタンスメソッドなどをうまく利用できる仕組みを提供してくれています。
それがセレクタと実装です。これらの対応表をテーブルにまとめておき、実行時にそれをルックアップして実行を決める、というのがざっくりとした説明です。

そして今回のサンプルではこの「実行時のルックアップ」を操作して、セレクタが指し示す実装を切り替えている、というわけです。

7
7
2

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?