如果對runtime有一定了解的話,一定聽說過或者用過這個函式:
1
void method_exchangeimplementations(method m1, method m2)
它通常叫做method swizzling,算是objc的"黑魔法"了,作用就是在程式執行期間動態的給兩個方法互換實現,比如有這樣一種使用場景:
我們的程式中有許多個viewcontroller,我想在對專案改動最小的情況下,在當每個controller執行完viewdidload以後就在控制台把自己的名字列印出來,方便我去做除錯或者了解專案結構。
有許多朋友會這樣說,讓所有控制器都繼承乙個basecontroller不就可以了嗎?我在這裡要解釋一下這樣做的缺點:假如你的專案裡有許多controller的話,你就需要把專案裡凡是沒有繼承自basecontroller的每個controller都做一次修改了,而且隨意更改層級結構會發生意想不到的錯誤。
其實我們的目的就是重寫viewdidload的方法,並在他的方法最後加上幾句log,所以我們需要給uiviewcontroller建立乙個category,因為我們知道,如果在catagory中重寫乙個方法,就會覆蓋它的原有方法實現,但是,這樣做以後就沒有辦法呼叫系統原有的方法,因為在乙個方法裡呼叫自己的方法會是乙個死迴圈。所以我們的解決辦法就是,另外寫乙個方法來和viewdidload「交換」,這樣外部呼叫viewdidload就會調到新建的這個方法中,同樣,我們呼叫新建的方法就會呼叫到系統的viewdidload中了。
imp指標
其實,還有一種更加簡單的方法可以讓我們辦到相同的目的,運用imp指標,imp就是implementation的縮寫,顧名思義,它是指向乙個方法實現的指標,每乙個方法都有乙個對應的imp,所以,我們可以直接呼叫方法的imp指標,來避免方法呼叫死迴圈的問題。
呼叫乙個imp的方式和呼叫普通c函式相同,比如:
1
id returnobjc = someimp(objc,sel,params...);
不過如果你的專案沒有做其他配置的話這樣呼叫編譯器是不會通過的,我們來看一下先它的定義:
1
2
3
4
5
if
!objc_old_dispatch_prototypes
typedef void (*imp)(void
/* id, sel, ... */
);
else
typedef id (*imp)(id, sel, ...);
endif
在預設情況下你的工程是開啟這個配置的
這種情況下imp被定義為無引數無返回值的函式。所以你需要到工程裡搜尋到這個選項並把它關閉。這樣的麻煩就是,每次使用,你都需要修改工程配置,所以這裡我再介紹另外一種辦法:重新定義乙個和有引數的imp指標相同的指標型別,在獲取imp時把它強轉為此型別。這樣運用imp指標後,就不需要額外的給viewcontroller寫新的方法:
還有乙個地方我們需要注意,如果這樣直接呼叫imp的話就會發生經典的exc_bad_access錯誤,我們定義的imp指標是乙個有返回值的型別,而其實我們獲取的viewdidload這個方法是沒有返回值的,所以我們需要新定義乙個和imp相同型別的函式指標比如vimp,把他的返回值定位void,這樣如果你修改的方法有返回值就用imp,沒有返回值就用vimp。
值得注意的是,如果你重寫的方法有返回值,不要忘記在最後做return。
總結
這是只是imp使用的場景之一,它還有許多作用,希望大家多多發現。
輕鬆學習之 IMP指標的作用
如果對runtime有一定了解的話,一定聽說過或者用過這個函式 1void method exchangeimplementations method m1,method m2 它通常叫做method swizzling,算是objc的 黑魔法 了,作用就是在程式執行期間動態的給兩個方法互換實現,比...
this指標 this 指標的作用
this 指標的作用 它的作用是指向成員函式作用於的物件,所以非靜態您可以在成員函式中直接使用它來表示指向該函式所作用的物件的指標。以下示例可以說明其作用 輸出結果 20000 20000 接下來,我們看下面的 您認為輸出結果是什麼?會出錯嗎?答案是正常輸出問候。您可能對p指標為空這一事實感到好奇。...
this指標的作用
對於類的非靜態成員,每個物件都有自己的乙份拷貝,即每個物件都有自己的資料成員,不過成員函式卻是每個物件共享的。那麼呼叫共享的成員函式是如何找到自己的資料成員?答案就是用this指標,下面舉例說明 當vbbook物件呼叫outputpages成員函式時,this指標指向vbbook物件,當vcbook...