国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網站 > 建站經驗 > 正文

iOS開發:教你動手實現objc_m,sgSend

2019-11-02 14:14:26
字體:
來源:轉載
供稿:網友

   objc_msgSend 函數支撐了我們使用 Objective-C 實現的一切。Gwynne Raskind,Friday Q&A 的讀者,建議我談談 objc_msgSend 的內部實現。要理解某件事還有比自己動手實現一次更好的方法嗎?咱們來自己動手實現一個 objc_msgSend。

  Tramapoline! Trampopoline! (蹦床)

  當你寫了一個發送 Objective-C 消息的方法:

  [obj message]

  編譯器會生成一個 objc_msgSend 調用:

  objc_msgSend(obj, @selector(message));

  之后 objc_msgSend 會負責轉發這個消息。

  它都做了什么?它會查找合適的函數指針或者 IMP,然后調用,最后跳轉。任何傳給 objc_msgSend 的參數,最終都會成為 IMP 的參數。 IMP 的返回值成為了最開始被調用的方法的返回值。

  因為 objcmsgSend 只是負責接收參數,找到合適的函數指針,然后跳轉,有時管這種叫做 trampoline(譯注:[蹦床](https://en.wikipedia.org/wiki/Trampoline(computing)). 更通用的來說,任何一段負責把一段代碼轉發到另一處的代碼,都可以被叫做 trampoline。

  這種轉發的行為使 objc_msgSend 變得特殊起來。因為它只是簡單的查找合適的代碼,然后直接跳轉過去,這相當的通用。傳入任何參數組合都可以,因為它只是把這些參數留給 IMP 去讀取。返回值有些棘手,但最終都可以看成 objc_msgSend 的不同變種。

  不幸的是,這些轉發行為都不能用純 C 實現。因為沒有方法可以將傳入 C 函數的泛參(generic parameters)傳給另一個函數。 你可以使用變參,但是變參和普通參數的傳遞方法不同,而且慢,所以這不適合普通的 C 參數。

  如果要用 C 來實現 objc_msgSend,基本樣子應該像這樣:

  id objc_msgSend(id self, SEL _cmd, ...)

  {

  Class c = object_getClass(self);

  IMP imp = class_getMethodImplementation(c, _cmd);

  return imp(self, _cmd, ...);

  }

  這有點過于簡單。事實上會有一個方法緩存來提升查找速度,像這樣:

  id objc_msgSend(id self, SEL _cmd, ...)

  {

  Class c = object_getClass(self);

  IMP imp = cache_lookup(c, _cmd);

  if(!imp)

  imp = class_getMethodImplementation(c, _cmd);

  return imp(self, _cmd, ...);

  }

  通常為了速度,cache_lookup 使用 inline 函數實現。

  匯編

  在 Apple 版的 runtime 中,為了最大化速度,整個函數是使用匯編實現的。在 Objective-C 中每次發送消息都會調用 objc_msgSend,在一個應用中最簡單的動作都會有成千或者上百萬的消息。

  為了讓事情更簡單,我自己的實現中會盡可能少的使用匯編,使用獨立的 C 函數抽象復雜度。匯編代碼會實現下面的功能:

  id objc_msgSend(id self, SEL _cmd, ...)

  {

  IMP imp = GetImplementation(self, _cmd);

  imp(self, _cmd, ...);

  }

  GetImplementation 可以用更可讀的方式工作。

  匯編代碼需要:

  1. 把所有潛在的參數存儲在安全的地方,確保 GetImplementation 不會覆蓋它們。

  2. 調用 GetImplementation。

  3. 把返回值保存在某處。

  4. 恢復所有的參數值。

  5. 跳轉到 GetImplementation 返回的 IMP。

  讓我們開始吧!

  這里我會嘗試使用 x86-64 匯編,這樣可以很方便的在 Mac 上工作。這些概念也可以應用于 i386 或者 ARM。

  這個函數會保存在獨立的文件中,叫做 msgsend-asm.s。這個文件可以像源文件那樣傳遞給編譯器,然后會被編譯并鏈接到程序中。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 岳池县| 米易县| 来宾市| 杂多县| 囊谦县| 鹤山市| 喜德县| 河源市| 廉江市| 溧水县| 宜昌市| 江川县| 柳江县| 广昌县| 天镇县| 广昌县| 日喀则市| 南岸区| 沁水县| 金溪县| 大关县| 塘沽区| 禹州市| 普定县| 广西| 三门县| 桐庐县| 上蔡县| 乐安县| 蓬莱市| 娄底市| 自治县| 凤翔县| 福清市| 吴旗县| 泰安市| 松潘县| 安图县| 姜堰市| 峨眉山市| 合水县|