objc/runtime.hでメソッド差し替え
objctive-cは、Objective-C 2.0 runtime library で、クラス情報の設定や取得ができる。メソッド差し替えのサンプル。
//
// main.m
// HelloCommand
//
// Created by on 12/04/15.
// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
// https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
#import
#import "MyHelloClass.h"
// 差し替えた関数。
// IMP型、関数ポインタ
// 第一引数が自身、第二引数が実行メソッド。
NSString* getHelloWorld(id self, SEL _cmd)
{
return @"RE DEFINED fnction!!!!";
}
/**
* objc/runtime.hで関数を差し替える。
*/
int main(int argc, const char * argv[])
{
@autoreleasepool {
MyHelloClass *myHelloClass = [[[MyHelloClass alloc]init] autorelease];
NSString *words = [myHelloClass getHelloWorld];
NSLog(@"%@", words);
NSString *className = [MyHelloClass getClassName:myHelloClass];
NSLog(@"クラス名取得:%@", className);
Class clazz = [MyHelloClass getClass:myHelloClass];
NSLog(@"クラスオブジェクト取得:%@", clazz);
Class superClass = class_getSuperclass(clazz);
NSLog(@"NSObjectが手に入るはず:%@", superClass);
// 独自クラス作成
NSString *newClassName = [NSString stringWithFormat:@"Custom%@", NSStringFromClass(clazz)];
NSLog(@"独自クラス:%@", newClassName);
Class mod = NSClassFromString(newClassName);
if (mod == nil) {
NSLog(@"z is nil");
// Creates a new class and metaclass.
Class superclass = clazz;
const char* utf8string_newClassName = [newClassName UTF8String];
mod = objc_allocateClassPair(superclass, utf8string_newClassName, 0);
// NSLog(@"modクラス:%@", mod);
SEL selectorToOverride1 = @selector(getHelloWorld);
Method m1 = class_getInstanceMethod([myHelloClass class], selectorToOverride1);
class_addMethod(mod, selectorToOverride1, (IMP)getHelloWorld, method_getTypeEncoding(m1));
objc_registerClassPair(mod);
} else {
NSLog(@"z is NOT nil");
}
// Sets the class of an object.
// arg1: instance, arg2: class
object_setClass(myHelloClass, mod);
NSLog(@"mod=%@", mod);
MyHelloClass *z = [[[mod alloc]init] autorelease];
NSLog(@"差し替えた関数が呼ばれる:%@", [z getHelloWorld]);
NSLog(@"myHelloClass is className =%@", myHelloClass);
}
return 0;
}
// // MyHelloClass.h // HelloCommand // // Created by on 12/04/15. // Copyright (c) 2012年 __MyCompanyName__. All rights reserved. // #import #import "objc/objc-runtime.h" @interface MyHelloClass : NSObject - (NSString *) getHelloWorld; + (NSString *) getClassName:id; + (Class) getClass:id; @end
//
// MyHelloClass.m
// HelloCommand
//
// Created by on 12/04/15.
// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//
#import "MyHelloClass.h"
@implementation MyHelloClass
- (NSString *) getHelloWorld
{
return @"hello world";
}
+ (NSString *) getClassName:(id)id
{
// NULL終端文字列で取得
const char *className = object_getClassName(id);
NSString *str;
str = [NSString stringWithCString:className encoding:NSUTF8StringEncoding];
//NSLog(@"className=%@", str);
return str;
}
+ (Class) getClass:(id)id
{
Class clazz = object_getClass(id);
return clazz;
}
@end
実行結果
2012-04-15 20:17:23.845 HelloCommand[9406:403] hello world 2012-04-15 20:17:23.847 HelloCommand[9406:403] クラス名取得:MyHelloClass 2012-04-15 20:17:23.848 HelloCommand[9406:403] クラスオブジェクト取得:MyHelloClass 2012-04-15 20:17:23.850 HelloCommand[9406:403] NSObjectが手に入るはず:NSObject 2012-04-15 20:17:23.851 HelloCommand[9406:403] 独自クラス:CustomMyHelloClass 2012-04-15 20:17:23.852 HelloCommand[9406:403] z is nil 2012-04-15 20:17:23.853 HelloCommand[9406:403] mod=CustomMyHelloClass 2012-04-15 20:17:23.853 HelloCommand[9406:403] 差し替えた関数が呼ばれる:RE DEFINED fnction!!!! 2012-04-15 20:17:23.854 HelloCommand[9406:403] myHelloClass is className =<CustomMyHelloClass: 0x7faf434142b0>
