iOS 函數調用的流程

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章