本文將要討論objective-c中的方法替換(method replacement)和swizzling(移魂**)。
overriding methods在任何物件導向語言中都很常見,主要用於子類化中。在子類中複寫乙個方法,然後在子類的例項就可以使用這個被重寫的方法。
對於乙個你無法控制其實例化(instantiation)的類,有時你或許會想複寫它的某個方法,雖然有點瘋狂。子類化可做不到,因為你沒有機會子類化你的子類。
posing是個很有趣的技術,不過已經過時了,因為64位和iphone環境下的objective-c runtime中不再支援它了. 通過這個偽裝(posing),你可子類化,然後將這個子類偽裝成它的父類。像變魔術一般,runtime會讓這個子類應用於各處,這時方法複寫又有了用處。既然被拋棄了,也就不必多費口舌了。
使用歸類(category)的技術,可以方便地為乙個已經存在的類複寫其方法:
@implementation
nsview
(myoverride)
-(void
)drawrect:
(nsrect)r
@end
這種方法其實僅僅適用於複寫目標類的父類中實現的函式。如果直接複寫目標類中的方法,使用歸類會帶來兩個問題:
它無法呼叫方法的之前的實現。替換掉後,之前的實現就被完全改寫了。但大部分情況下,只是想增加些功能,並不期望完全替代。
如果被多個category複寫,執行時(runtime)並不保證哪個真正會被使用到。
使用乙個稱為swizzling的技術,可以為歸類(category)解決上面兩個問題,既可以呼叫舊的實現,又可以避免多個category帶來的不確定性。它的秘訣是使用乙個不同的函式名來複寫,然後由執行時(runtime)交換它們。
首先,用乙個不同的名字複寫:
@implementation
nsview
(myoverride)
-(void
)override_drawrect:
(nsrect)r
@end
(譯註:呵呵,不知道你是不是和我一樣,初次看到**還以為是個遞迴呼叫呢。) 其實是這個新的方法在執行時已經和原先的函式對調了(現在還沒做到,往下看!)。在執行時,呼叫 override_drawrect: 方法其實就是呼叫舊的實現。
接下來,你還要寫些**才能完成交換:
void
methodswizzle
(class c,
selorigsel,
seloverridesel)
(譯註:addmethod會讓目標類的方法指向新的實現,使用replacemethod再將新的方法指向原先的實現,這樣就完成了交換操作。)
如果新增失敗了,就是第二情況(在目標類重寫的方法)。這時可以通過method_exchangeimplementations來完成交換:
else
} 對於第二種情況,因為class_getinstancemethod 會返回父類的實現,如果直接替換,就會替換掉父類的實現,而不是目標類中的實現。(詳細的函式說明在)
舉個具體的例子, 假設要替換掉-[nsview description]. 如果nsview 沒有實現-description (可選的) 那你就可會得到nsobject的方法。如果呼叫method_exchangeimplementations , 你就會把nsobject 的方法替換成你的**。這應該不會是你想要的吧?
最後在乙個合適位置呼叫一下就可以了。比如在乙個+load 方法中呼叫: +
(void
)load
前面的內容確實有些難懂。swizzling的概念的確顯得有些古怪,特別是在函式中轉來轉去的,多少讓人有些思維扭曲的感覺。我下面要介紹乙個更為簡潔,也更容易理解和實現的方式。
這種方式不再需要儲存舊有的方法,也不必動態的區分[self override_drawrect: r] 。我們從頭實現。
相對於將原有的方法存放於乙個新的方法中,這裡使用乙個全域性指標來儲存:
void(*
gorigdrawrect)(id,
sel, nsrect);
然後在+load 裡賦值: +
(void
)load
當然,這個方法不是那麼優雅,不過我認為它更易於運用。
複寫不是你自家的類是危險的! 盡量避免這麼做,要不然就盡最大的可能細心處理。
fridayqa,2010-01-29, method replacement for fun and profit
參考:
Objective c 方法的呼叫
在書寫了類的宣告和實現後,應用程式如何去呼叫它呢?在objective c中,呼叫方法的簡單格式如下 1 例項 方法 如 person setage 32 其中 person是person類的例項。或者是 2 類名 方法名 如 nsstring str nsdate date 這是直接呼叫類nsda...
Objective c 方法的呼叫
在書寫了類的宣告和實現後,應用程式如何去呼叫它呢?在objective c中,呼叫方法的簡單格式如下 1 例項 方法 如 person setage 32 其中 person是person類的例項。或者是 2 類名 方法名 如 nsstring str nsdate date 這是直接呼叫類nsda...
Objective C構造方法
構造方法 用來初始化的方法 之前我們建立物件的方式一直是使用 new 但是使用new建立的物件,都是給我們預設做了初始化的。有的時候,我們需要按照我們自己的需求進行初始化,那麼怎麼做呢 首先了解一下,我們使用new建立物件的時候,都做了什麼事情。分配儲存空間 alloc 呼叫類方法alloc來給物件...