国产探花免费观看_亚洲丰满少妇自慰呻吟_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。這個文件可以像源文件那樣傳遞給編譯器,然后會被編譯并鏈接到程序中。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 祁连县| 三原县| 洪泽县| 牟定县| 松阳县| 潞城市| 抚顺市| 廊坊市| 金堂县| 高淳县| 长寿区| 西藏| 龙泉市| 崇仁县| 施秉县| 延长县| 伊金霍洛旗| 胶州市| 长沙市| 葫芦岛市| 博兴县| 桐乡市| 都昌县| 洪洞县| 阿克苏市| 凯里市| 崇文区| 五指山市| 大田县| 新源县| 兴山县| 浪卡子县| 贵港市| 沙雅县| 敖汉旗| 新平| 教育| 淳化县| 保德县| 旬阳县| 鹤壁市|