OC是一門動態語言,一個函數是由一個selector(SEL),和一個implement(IML)組成的。selector相當於地址,而implement纔是真正的房間。和我們網購一樣,地址可以隨意寫。但不一定都能找到收件人。如果找不到系統會給程序幾次機會來使程序正常運行,之後依然不行纔會拋出異常。
下面用代碼來實際演示一下。建議每個方法都打上斷點,這樣能夠理解函數的執行順序。
#import "RunTimeTest.h"
#import <objc/runtime.h>
@interface RunTimeChild : NSObject
@end
@implementation RunTimeChild
- (void)resolveThisMethodDynamically2
{
NSLog(@"resolveThisMethodDynamically");
}
@end
@interface RunTimeTest()
@end
@implementation RunTimeTest
@dynamic name ,age;
- (id)init
{
if (self = [super init]) {
_mutableDic = [NSMutableDictionary dictionary];
[_mutableDic setObject:@"bnm" forKey:@"uio"];
[_mutableDic setObject:@"xiaoming" forKey:@"name"];
}
return self;
}
void dynamicMethodIMP(id self,SEL _cmd)
{
NSLog(@"dynamicMethodIMP");
}
/*
* 這個函數在當前類執行時沒有找到對應的SEL的IML時就會執行,這個函數是給類利用class_addMethod動態添加函數的機會
* 如果實現了添加函數代碼則返回YES,否則返回NO。
* 提醒下這裏是否繼續執行之後的流程不是以resolveInstanceMethod返回值爲準的,而是以是否找到對應SEL爲標準
*/
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");
}
return YES;
}
/*
執行到這個函數,系統將給了個將這個SEL轉給其他對象的機會
返回參數一個對象,如果這個對象非空,非self,系統會將運行的消息轉發給這個對象執行。
*/
- (id)forwardingTargetForSelector:(SEL)aSelector
{
RunTimeChild *child = [[RunTimeChild alloc] init];
//return child; //取消註釋會將SEL轉移至這個對象中
return nil;
}
/*
這個函數與forwardInvocation是最後尋找SEL的機會。這個函數讓重載方有機會拋出一個函數的簽名,再由後面的forwardInvocation去執行
*/
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSString *sel = NSStringFromSelector(aSelector);
if ([sel rangeOfString:@"set"].location == 0) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}else{
return [NSMethodSignature signatureWithObjCTypes:"@@:"];
}
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSString *key = NSStringFromSelector([anInvocation selector]);
if ([key rangeOfString:@"set"].location == 0) {
key = [[key substringWithRange:NSMakeRange(3, [key length] - 4)] lowercaseString];
NSString *obj;
[anInvocation getArgument:&obj atIndex:2];
NSLog(@"%@",obj);
[_mutableDic setObject:obj forKey:key];
}else{
NSString *obj = [_mutableDic objectForKey:key];
NSLog(@"%@",key);
[anInvocation setReturnValue:&obj];
}
}
@end
調用方法:
#import "ViewController.h"
#import "RunTimeTest.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
RunTimeTest *runTime = [[RunTimeTest alloc] init];
// SEL S = NSSelectorFromString(@"uio");
runTime.age = @"18";
NSString *f = [runTime age];
NSLog(@"%@",f);
// objc_msgSend((id)runTime,S);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
代碼下載:http://download.csdn.net/detail/qqmcy/9450669