程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Objective-C方法的調用流程詳解

Objective-C方法的調用流程詳解

編輯:關於C語言

Objective-C方法的調用流程詳解


在Objective-C中,方法會在運行時轉換成一個消息函數的的調用,即objc_msgSend。其基本形式是objc_msgSend(receiver, selector, arg1, arg2, ...)。第一個參數是消息接受者,第二個參數是一個SEL類型的數據,其余的為消息的參數。

等等,如果您對基本方法基本的概念還不太清晰的話,請參閱一下另一篇文章。如果有了基本的概念性基礎後,我們來進行流程的解析。

定義一個男人類,裡面沒有多余的代碼。

@interface Man : NSObject
@end
@implementation Man
@end


1. 如果selector是一些內存管理相關的消息(如retain,release,retainCount等),則直接返回接收者。

2. 如果沒有接受者則返回為空(nil,0,或者{0})

3. 接下來接受者會在對象結構體中緩存的方法鏈表中尋找selector,如果尋找到就進行方法的調用。如果沒有找到,則繼續在所有的方法鏈表中尋找,如果尋找到了,則進行方法的調用,並且把這個selector存在緩存鏈表中。假如在對象的結構體中沒有尋找到這個selector,則會一級一級的在父類的方法鏈表中尋找,直到NSObject停止。

\

這些流程和大部分的語言相似,但是Objective-C並不止如此,它還會進行更多的檢測和操作,從而進一步挽救大家“脆弱”的程序。

4. 挽救第一步:利用resolveInstanceMethod:進行自救<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqOto62jrTxzdHJvbmc+tq/MrLe9t6i94s72PC9zdHJvbmc+PC9wPgo8cD682cno1eK49sTQyMu7ucvjx9rAzaOs19S8urvh1/a3uaOsy/nS1Lao0uXSu7j21/a3ubXEt723qKGj1NpNYW4uaNbQvNPI68jnz8K3vbeoPC9wPgo8cD48L3A+CjxwcmUgY2xhc3M9"brush:java;">- (NSString *)makeSomeFood:(NSString *)food; //做飯 但是在Man.h中不去實現它,因為他不知道今天到底有沒有肉,如果有肉就做肉吃,沒有就做大白菜吃。在Man.m中加入如下代碼

static id makeVegetable (id self, SEL _cmd, id value)
{
    NSString *intentedFood = (NSString *)value;
    return [NSString stringWithFormat:@"本來打算做%@吃,現在只有做大白菜吃了",intentedFood];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSString *selStr = NSStringFromSelector(sel);
    if ([selStr isEqualToString:@"makeSomeFood:"]) {
        class_addMethod([Man class], sel, (IMP)makeVegetable, "v@:@");
    }
    return [super resolveInstanceMethod:sel];
}


resolveInstanceMethod:方法中先判斷方法名稱,如果是makeSomeFood:方法,則在運行時動態的添加一個makeVegetable方法去進行方法處理並放回結果。class_addMethod的第一個參數是類名,第二個參數是方法名稱,第三個是函數實現地址,第四個參數是類型編碼參數。

5. 挽救第二步:利用forwardingTargetForSelector:進行求助---備用接受者

假設這個男人想生一個孩子,他必然得求助他老婆啦,當然前提有願意替他生孩子的老婆。

定義Wife類

@interface Wife : NSObject
@end
@implementation Wife
- (void)giveBirthToBaby
{
    NSLog(@"生孩子啦");
}
@end


//Man.h中添加方法
@property (nonatomic, retain) Wife *mWife;
- (void)giveBirthToBaby; //生孩子


//Man.m中實現
- (id)forwardingTargetForSelector:(SEL)aSelector{ 
    if ([_mWife respondsToSelector:aSelector]) { 
        return _mWife; 
    } 
        return [super forwardingTargetForSelector:aSelector];
}


//初始化的時候
Man *people = [[Man alloc] init];
people.mWife = Wife.new;
[people giveBirthToBaby]; 

當調用giveBirthToBaby:時,會執行第四步去檢查自己能不能自力更生解決問題,當沒法解決的時候會讓_mWife去實現相應的方法,從表面上看時Man去實現了這個方法。

這裡需要注意一點的是:由於是讓新對象去執行這個方法,一個必要的流程也是如果這個新對象也沒有實現方法,就會去父類中找實現方法,如果找到了就調用並存儲到緩存鏈表中,沒有找到則沒法實現會拋出異常,繼續接下來的拯救方法。

6. 挽救第三步:利用forwardInVocation:進行外包---完整消息轉發假設這個男人現在想要制造一個大飛機,雖然是土豪,但是最多也只能是外包給朋友去解決了。

定義能解決問題的土豪朋友類:

@interface RichFriend : NSObject
@end
@implementation RichFriend
- (void)makeSomeAirplane:(NSString *)airPlaine
{
    NSLog(@"%@",[NSString stringWithFormat:@"制造%@成功",airPlaine]);
}
@end

//Man.h中添加方法
- (void)makeSomeAirplane:(NSString *)airPlaine;       //造飛機

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *sig = [super methodSignatureForSelector:aSelector];
    if (!sig) {
        if ([RichFriend instancesRespondToSelector:aSelector]) {
            sig = [RichFriend instanceMethodSignatureForSelector:aSelector];
        }
    }
    return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    if ([RichFriend instancesRespondToSelector:anInvocation.selector])
    {
        [anInvocation invokeWithTarget:RichFriend.new];
    } else {
        [super forwardInvocation:anInvocation];
    }
}


//初始化
Man *people = [[Man alloc] init];
[people makeSomeAirplane:@"A380"];
如果第四和第五部都沒法解決問題,那麼只能是最後一步進行NSInVocation進行轉發,NSInvocation是一個包含receiver,selector,parameter 等的一個封裝類,把所有相關的信息進行打包處理。首先需要通過methodSignatureForSelector:方法獲得selector的方法簽名建立NSInvocation對象,這個對象可以通過invokeWithTarget:方法驅動新的接受者去進行消息的處理。

如果這一步也沒有進行消息的處理,NSObject 的forwardInVocation:就會調用doesNotRecognizeSelector:方法,程序就崩潰啦。

最後上圖:



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved