咱們在初學Objective-C時,都會以爲ObjC中的消息傳遞和其餘語言的調用函數差很少,只是在OC中,方法調用用消息傳遞這一律念來代替。c++
那麼到底怎樣區別OC中的消息傳遞與其餘語言的調用函數呢。程序員
可使用C語言與OC語言進行一下對比。編程
C語言示例數據結構
//聲明一個函數,用來獲取兩個整型值的中較大的值int max(int a,int b); int main(int argc, const char * argv[]) { //調用函數,獲取4,6兩個整型值的最大值 int result = max(4,6); //打印結果 printf("4與6兩個數的較大的值是:%d",result); return 0; }
編譯運行程序以後,編譯器會提示以下錯誤app
Undefined symbols for architecture x86_64: "_max", referenced from: _main in main.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
在如上的例子中,咱們可以體會到調用函數的語言在聲明完函數後,若是沒有實現函數,程序是沒法編譯經過的。函數
那麼咱們接下來看工具
OC的例子ui
#import <Foundation/Foundation.h>@interface Function : NSObject//聲明一個類方法,用來獲取兩個整型值的最大值+ (int)max:(int)v1 :(int)v2;@end#import "Function.h"@implementation Function@end
只使用Xcode工具的build功能(Command+B),咱們可以看到程序是能夠編譯經過的,可是會有一個黃色的警告spa
Method definition for 'max::' not found!
只有當程序運行以後纔會出現以下的崩潰信息指針
+[Function max::]: unrecognized selector sent to class 0x1000010f8*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[Function max::]: unrecognized selector sent to class 0x1000010f8'*** First throw call stack: ( 0 CoreFoundation 0x00007fff8ea9925c __exceptionPreprocess + 172 1 libobjc.A.dylib 0x00007fff88555e75 objc_exception_throw + 43 2 CoreFoundation 0x00007fff8ea9c02d +[NSObject(NSObject) doesNotRecognizeSelector:] + 205 3 CoreFoundation 0x00007fff8e9f7272 ___forwarding___ + 1010 4 CoreFoundation 0x00007fff8e9f6df8 _CF_forwarding_prep_0 + 120 5 SendMethod 0x0000000100000f24 main + 68 6 libdyld.dylib 0x00007fff8a8f95fd start + 1) libc++abi.dylib: terminating with uncaught exception of type NSException
經過這種形式的對比,相信你們應該對消息傳遞和調用函數的形式上的區別應該可以看出來了。
對,消息傳遞和調用函數對於程序員來講最大的區別就在於源代碼編譯的過程當中是否可以編譯經過.
解釋消息傳遞機制的原理就要用到OC語言中的運行時系統(Runtime)了.
運行時系統是一個提供一系列公開函數接口以及數據結構的動態連接庫,這些頭文件位於/usr/include/objc。許多這些函數容許你使用純C語言重寫當你寫OC代碼後編譯器作的事情。其餘形式的接口則是經過NSObject類中定義的一些方法。這些方法是能夠用來實現其餘的運行時接口來提升運行效率。可是重寫運行時的代碼對於使用OC語言進行編程並不是是必須的,可是,少數的運行時函數在一些特殊狀況下,對於OC程序仍是頗有用途的。
接下來,咱們一塊兒看一下這些函數。
Objc_msgSend()函數舉例
#import <Foundation/Foundation.h>@interface Function : NSObject//聲明一個類方法,用來獲取兩個整型值的最大值+ (int)max:(int)v1 :(int)v2;@end#import "Function.h"@implementation Function+ (int)max:(int)v1 :(int)v2 { return v1 > v2 ? v1:v2; }@end
根據以上的Function類,使用objc_msgSend()這種c語言的函數完成oc方法的調用。
//獲取4,6兩個整型值的最大值 int result = (int)objc_msgSend([Function class], @selector(max::),4,6); //打印結果 NSLog(@"4,6的最大值是:%d",result);
消息傳遞函數爲動態綁定提供全部必要的內容:
首先,它找到選擇器調用的過程(方法實現)。因爲同一個方法在不一樣的類中可能有不一樣的實現,這個精確的調用過程依賴於接收者所屬於的類。
而後,它會調用這個過程,傳遞接收者對象(一個指向其數據的指針),以及消息中定義的那些參數。
最後,它傳遞過程調用的返回值做爲它自身的返回值。
注意:編譯器會自動調用消息傳遞函數。你不該該在本身的代碼中直接調用該方法。