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