1. 程式人生 > >iOS 函式呼叫的流程

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, "
[email protected]
:"); } 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:"
[email protected]
:@"]; }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