iOS學習筆記:Runtime

原文鏈接:Associated Objects

Patterns

  • Adding private variables to facilitate implementation details. When extending the behavior of a built-in class, it may be necessary to keep track of additional state. This is the textbook use case for associated objects. For example, AFNetworking uses associated objects on its UIImageView category to store a request operation object, used to asynchronously fetch a remote image at a particular URL.
  • Adding public properties to configure category behavior. Sometimes, it makes more sense to make category behavior more flexible with a property, than in a method parameter. In these situations, a public-facing property is an acceptable situation to use associated objects. To go back to the previous example of AFNetworking, its category on UIImageView, its imageResponseSerializer allows image views to optionally apply a filter, or otherwise change the rendering of a remote image before it is set and cached to disk.
  • Creating an associated observer for KVO. When using KVO in a category implementation, it is recommended that a custom associated-object be used as an observer, rather than the object observing itself.

Anti-Patterns

  • Storing an associated object, when the value is not needed. A common pattern for views is to create a convenience method that populates fields and attributes based on a model object or compound value. If that value does not need to be recalled later, it is acceptable, and indeed preferable, not to associate with that object.
  • Storing an associated object, when the value can be inferred. For example, one might be tempted to store a reference to a custom accessory view's containing UITableViewCell, for use in tableView:accessoryButtonTappedForRowWithIndexPath:, when this can retrieved by calling cellForRowAtIndexPath:.
  • Using associated objects instead of X, where X is any one the following:

Associated objects should be seen as a method of last resort, rather than a solution in search of a problem (and really, categories themselves really shouldn't be at the top of the toolchain to begin with).


原文鏈接:Method Swizzling

+load vs. +initialize

Swizzling should always be done in +load.

There are two methods that are automatically invoked by the Objective-C runtime for each class. +load is sent when the class is initially loaded, while +initialize is called just before the application calls its first method on that class or an instance of that class. Both are optional, and are executed only if the method is implemented.

Because method swizzling affects global state, it is important to minimize the possibility of race conditions. +load is guaranteed to be loaded during class initialization, which provides a modicum of consistency for changing system-wide behavior. By contrast, +initialize provides no such guarantee of when it will be executed—in fact, it may never be called, if that class is never messaged directly by the app.

dispatch_once

Swizzling should always be done in a dispatch_once.

Again, because swizzling changes global state, we need to take every precaution available to us in the runtime. Atomicity is one such precaution, as is a guarantee that code will be executed exactly once, even across different threads. Grand Central Dispatch's dispatch_once provides both of these desirable behaviors, and should be considered as much a standard practice for swizzling as they are for initializing singletons.

Selectors, Methods, & Implementations

In Objective-C, selectors, methods, and implementations refer to particular aspects of the runtime, although in normal conversation, these terms are often used interchangeably to generally refer to the process of message sending.

Here is how each is described in Apple's Objective-C Runtime Reference:

  • Selector (typedef struct objc_selector *SEL): Selectors are used to represent the name of a method at runtime. A method selector is a C string that has been registered (or "mapped") with the Objective-C runtime. Selectors generated by the compiler are automatically mapped by the runtime when the class is loaded .
  • Method (typedef struct objc_method *Method): An opaque type that represents a method in a class definition.
  • Implementation (typedef id (*IMP)(id, SEL, ...)): This data type is a pointer to the start of the function that implements the method. This function uses standard C calling conventions as implemented for the current CPU architecture. The first argument is a pointer to self (that is, the memory for the particular instance of this class, or, for a class method, a pointer to the metaclass). The second argument is the method selector. The method arguments follow.

The best way to understand the relationship between these concepts is as follows: a class (Class) maintains a dispatch table to resolve messages sent at runtime; each entry in the table is a method (Method), which keys a particular name, the selector (SEL), to an implementation (IMP), which is a pointer to an underlying C function.

To swizzle a method is to change a class's dispatch table in order to resolve messages from an existing selector to a different implementation, while aliasing the original method implementation to a new selector.

Considerations

Swizzling is widely considered a voodoo technique, prone to unpredictable behavior and unforeseen consequences. While it is not the safest thing to do, method swizzling is reasonably safe, when the following precautions are taken:

  • Always invoke the original implementation of a method (unless you have a good reason not to): APIs provide a contract for input and output, but the implementation in-between is a black box. Swizzling a method and not calling the original implementation may cause underlying assumptions about private state to break, along with the rest of your application.
  • Avoid collisions: Prefix category methods, and make damn well sure that nothing else in your code base (or any of your dependencies) are monkeying around with the same piece of functionality as you are.
  • Understand what's going on: Simply copy-pasting swizzling code without understanding how it works is not only dangerous, but is a wasted opportunity to learn a lot about the Objective-C runtime. Read through the Objective-C Runtime Reference and browse <objc/runtime.h> to get a good sense of how and why things happen. Always endeavor to replace magical thinking with understanding.
  • Proceed with caution: No matter how confident you are about swizzling Foundation, UIKit, or any other built-in framework, know that everything could break in the next release. Be ready for that, and go the extra mile to ensure that in playing with fire, you don't get NSBurned.

原文鏈接: Objective-C Runtime

Objective-C

Objective-C 擴展了 C 語言,并加入了面向對象特性和 Smalltalk 式的消息傳遞機制。而這個擴展的核心是一個用 C 和 編譯語言 寫的 Runtime 庫。它是 Objective-C 面向對象和動態機制的基石。

Objective-C 是一個動態語言,這意味著它不僅需要一個編譯器,也需要一個運行時系統來動態得創建類和對象、進行消息傳遞和轉發。理解 Objective-C 的 Runtime 機制可以幫我們更好的了解這個語言,適當的時候還能對語言進行擴展,從系統層面解決項目中的一些設計或技術問題。了解 Runtime ,要先了解它的核心 - 消息傳遞 (Messaging)。

Objective-C 中給一個對象發送消息會經過以下幾個步驟:

  • 在對象類的 dispatch table 中嘗試找到該消息。如果找到了,跳到相應的函數IMP去執行實現代碼;
  • 如果沒有找到,Runtime 會發送 +resolveInstanceMethod: 或者 +resolveClassMethod: 嘗試去 resolve 這個消息;
  • 如果 resolve 方法返回 NO,Runtime 就發送 -forwardingTargetForSelector: 允許你把這個消息轉發給另一個對象;
  • 如果沒有新的目標對象返回, Runtime 就會發送 -methodSignatureForSelector: 和 -forwardInvocation: 消息。你可以發送 -invokeWithTarget: 消息來手動轉發消息或者發送 -doesNotRecognizeSelector: 拋出異常。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容