iOS直接調(diào)用函數(shù)和調(diào)用函數(shù)指針的區(qū)別與原理

函數(shù)和函數(shù)指針調(diào)用時候的區(qū)別:

區(qū)別:運行效率不同 ,直接調(diào)用函數(shù)指針運行效率高(ps:大量數(shù)據(jù)的時候)

?原因:調(diào)用函數(shù)的時候番挺,由于runtime機制,通過方法objc_msgSend() 把函數(shù)的調(diào)用對象和方法名發(fā)送出去

根據(jù)對象名找到對象類存儲的函數(shù)函數(shù)列表MethordList,再根據(jù)方法名找到MethordList 中的函數(shù)指針method_imp吗浩,再根據(jù)函數(shù)指針調(diào)用響應(yīng)函數(shù)

實現(xiàn)原理

任意一個NSObject的對象都有一個屬性isa 建芙,指向?qū)ο髮?yīng)的Class

@interface NSObject ?{

? ?Class isa ?OBJC_ISA_AVAILABILITY;

}

根據(jù)對象調(diào)用即可拿到對應(yīng)的Class ,Class 是純C的結(jié)構(gòu)體

typedef struct objc_class *Class;

struct objc_class {

? ?Class isa; // 指向metaclass

?? Class superclass; ?// 指向父類Class

? ?const char *name; ?// 類名

uint32_t version; ?// 類的版本信息

uint32_t info; ? ? ? ?// 一些標識信息懂扼,標明是普通的Class還是metaclass

uint32_t instance_size; ? ? ? ?// 該類的實例變量大小(包括從父類繼承下來的實例變量);

struct old_ivar_list *ivars; ? ?//類中成員變量的信息

struct old_method_list **methodLists; ? ?類中方法列表

Cache cache; ? ?查找方法的緩存禁荸,用于提升效率

struct old_protocol_list *protocols; ?// 存儲該類遵守的協(xié)議

}

由上面的代碼可以看出Class是一個結(jié)構(gòu)體指針,只想objc_class 結(jié)構(gòu)體阀湿。在object_class中存放著methodLists赶熟,所以我們可以根據(jù)Class找到方法列表

下面我們來看看怎么從methodLists中找到對應(yīng)的函數(shù)指針

struct old_method_list {

? ?void *obsolete; ? ? ? ?//廢棄的屬性

? ?int method_count; ? ?//方法的個數(shù)

? ?/* variable length structure */

? ?struct old_method method_list[1]; ? ?方法的首地址

};


struct old_method {

? ?SEL method_name; ? ?//方法對應(yīng)的SEL

? ?char *method_types; ? ? ? ?//方法的類型

? ?IMP method_imp; ? ? ? ?//方法對應(yīng)的函數(shù)指針

};


對于old_method_list結(jié)構(gòu)體,他存儲了old_method方法個數(shù)和方法首地址陷嘴。我們可以把他當做一個可變長度的old_method數(shù)組映砖。

注:

method_list[1],數(shù)組的大小怎么會是1呢灾挨?由于數(shù)組的大小是不定的邑退,不同的類對應(yīng)的不同的方法個數(shù)。所以定義時只存儲首地址劳澄,在實際使用過程中再擴展長度

對于old_method結(jié)構(gòu)體地技,他由SEL,type秒拔,IMP三個成員組成莫矗。由此可知,我們只要在method_list中找到了old_method即可拿到函數(shù)指針I(yè)MP砂缩。下面是查找的代碼:

static inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) {

? ?int i;

? ?if (!mlist) return nil;

? ?for (i = 0; i < mlist->method_count; i++) {

? ? ? ?old_method *m = &mlist->method_list[i];

? ? ? ?if (m->method_name == sel) {

? ? ? ? ? ?return m;

? ? ? ?}

? ?}

? ?return nil;

}

1. 查找函數(shù)是個內(nèi)聯(lián)函數(shù)作谚,傳入old_method_list和SEL,返回old_method

2. 首先對old_method_list數(shù)組判空庵芭,如果為空妹懒,返回nil

3. 遍歷old_method_list數(shù)組,根據(jù)SEL匹配双吆,找到old_method

4眨唬、函數(shù)調(diào)用的性能優(yōu)化

4.1 ?SEL的使用

說明:蘋果官方對SEL的解釋是:一種不透明的類型滔悉,它代表著一個方法選擇器。SEL本質(zhì)其實是一個int類型的地址单绑,指向存儲的方法名。對于每一個類曹宴,都會分配一塊特殊空空間搂橙,專門存儲類中的方法名,SEL就是指向?qū)?yīng)方法名的地址笛坦。由于方法名字符串是唯一的区转,所以SEL也是唯一的。

類型:(int)型版扩,原因:方便效率高

4.2 cache(快速緩存區(qū))


我們來仔細分析一下函數(shù)的調(diào)用過程:

obj->isa->methodLists

old_method->method_imp

1. 由于isa是obj的成員變量废离,methodLists是isa的成員變量,所以用obj可以直接拿到methodLists

2. 由于method_imp是old_method的成員變量礁芦,所以用old_method可以直接拿到method_imp 所以函數(shù)調(diào)用過程的主要時間消耗在methodLists中查找old_method蜻韭。cache就是用來優(yōu)化這個查找過程的。我們可以把cache簡單當成一個哈希表柿扣,key是SEL肖方,Value是old_method。由此可知未状,從cache中查找old_method相當簡單高效俯画。從methodLists中查找old_method的真正過程分為如下兩步:

? ?1. 通過SEL在cache中查找old_method,若找到了直接返回司草,若未找到執(zhí)行2

? ?2. 在methodLists中查找old_method艰垂,找到之后先將old_method插入cache中以方便下次查找,再返回old_method 由此可知埋虹,在第一次調(diào)用某個函數(shù)時猜憎,會比較慢,因為cache中沒有這個函數(shù)吨岭,第二次調(diào)用時就會非忱冢快了

查找方式,先從cache 中尋找辣辫,如果沒有旦事,去改對象索引出來的方法列表,如果依然沒有找到急灭,繼續(xù)向上層類尋找姐浮,如果仍然沒有找到,并且實現(xiàn)了動態(tài)方法決議機制葬馋,就進行決議卖鲤,如果沒有實現(xiàn)動態(tài)決議機制或則決議肾扰,如果無論在哪一層的都會存在cache 中,方便下次調(diào)用

該博客是瀏覽大神博客之后根據(jù)自己的理解蛋逾,并親自試驗完成的集晚,如有雷同,純屬借鑒区匣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偷拔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亏钩,更是在濱河造成了極大的恐慌莲绰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姑丑,死亡現(xiàn)場離奇詭異蛤签,居然都是意外死亡,警方通過查閱死者的電腦和手機栅哀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門震肮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人留拾,你說我怎么就攤上這事钙蒙。” “怎么了间驮?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵躬厌,是天一觀的道長。 經(jīng)常有香客問我竞帽,道長扛施,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任屹篓,我火速辦了婚禮疙渣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堆巧。我一直安慰自己妄荔,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布谍肤。 她就那樣靜靜地躺著啦租,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荒揣。 梳的紋絲不亂的頭發(fā)上篷角,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音系任,去河邊找鬼恳蹲。 笑死虐块,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的嘉蕾。 我是一名探鬼主播贺奠,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼错忱!你這毒婦竟也來了敞嗡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤航背,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棱貌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玖媚,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年婚脱,在試婚紗的時候發(fā)現(xiàn)自己被綠了今魔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡障贸,死狀恐怖错森,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情篮洁,我是刑警寧澤涩维,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站袁波,受9級特大地震影響瓦阐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜篷牌,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一睡蟋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枷颊,春花似錦戳杀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至题造,卻和暖如春坐求,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晌梨。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工桥嗤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留须妻,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓泛领,卻偏偏與公主長得像荒吏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子渊鞋,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉绰更,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,686評論 0 9
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現(xiàn)在哪呢锡宋?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,182評論 0 7
  • runtime 和 runloop 作為一個程序員進階是必須的儡湾,也是非常重要的, 在面試過程中是經(jīng)常會被問到的执俩, ...
    made_China閱讀 1,203評論 0 7
  • runtime 和 runloop 作為一個程序員進階是必須的徐钠,也是非常重要的, 在面試過程中是經(jīng)常會被問到的役首, ...
    SOI閱讀 21,791評論 3 63
  • coding 的演示功能不讓用尝丐,原來搭建的博客訪問不了了。索性將全部博客遷移到簡書衡奥,這篇是舊文章爹袁,歡迎大家以后來簡...
    小笨狼閱讀 1,063評論 1 6