Foundation中的類簇和Swizzle

2021-09-24 07:18:57 字數 2731 閱讀 4771

我們都知道swizzle method在oc中是一種有趣又實用的技巧,現在假設我們想hook掉nsmutablearray的insertobject:atindex:方法,我們會在nsmutablearray的分類中這樣寫:

swizzleinstancemethod([self class], @selector(insertobject:atindex:), @selector(swizzle_insertobject:atindex:));

複製**

然而我們會發現雖然swizzle成功了,但是實際上並沒有執行swizzle_insertobject:atindex:方法,這是為什麼呢?

我們先寫個測試**:

nsstring *nilstr = nil;

[[nsmutablearray array] addobject:nilstr];

複製**

看下下面的錯誤資訊:

複製**

__nsarraym是個什麼鬼?這就是導致我們上面swizzle method後,swizzle_insertobject:atindex:不執行的原因。

再來看以下的列印資訊:

(lldb) po [[nsmutablearray alloc] init]

<__nsarraym 0x7fb452e04a20>(

)(lldb) po [nsmutablearray array]

<__nsarraym 0x7fb452d0ba30>(

)(lldb) po [nsmutablearray arraywithobject:@""];

<__nsarraym 0x7fb452d0baf0>(

)(lldb) po [[nsmutablearray alloc] class]

__nsplaceholderarray

(lldb) po [nsarray array]

<__nsarray0 0x7fb452d05910>(

)(lldb) po [[nsarray alloc] init]

<__nsarray0 0x7fb452d05910>(

)(lldb) po @

<__nsarray0 0x7fb452d05910>(

)(lldb) po [[nsarray alloc] class]

__nsplaceholderarray

(lldb) po [[nsarray alloc] initwithobjects:@"", nil];

<__nsarrayi 0x7fb452f059c0>(

)(lldb)

複製**

仔細看其中的端倪,

[nsmutablearray array]  // __nsarraym 型別(mutable)

[nsarray array] // __nsarray0 型別 (空 immutable)

[[nsarray alloc] initwithobjects:@"", nil] // __nsarrayi 型別(immutable)

[[nsarray alloc] class] // __nsplaceholderarray

[[nsmutablearray alloc] class] // __nsplaceholderarray

複製**

可以看出,這些列印的型別是蘋果隱藏起來的array的實際型別,因此我們在文章開頭的hook掉的是 [nsmutablearray class] 中的方法,並不是我們真正在專案中呼叫的__nsarraym的 方法,所以並沒有執行我們的swizzle_method。(有個小細節,3種方式列印的空不可變陣列__nsarray0指向同乙個位址)

那該怎麼解決這個問題?方法也很簡單,現在知道了源方法屬於哪個型別,那麼我們就對這個型別實用swizzlemethod:

nsmutablearray *mutarray = [nsmutablearray array];

swizzleinstancemethod([mutarray class], @selector(insertobject:atindex:), @selector(swizzle_insertobject:atindex:));

複製**

上面還有乙個奇怪的型別__nsplaceholderarray,這個又是幹嘛的,在上面的參考鏈結中有它的解釋,我們這裡討論它和swizzle method有什麼關聯,其實如果我們想hook掉nsarray的 init 方法的話就需要用到它了,**如下:

nsarray *placeholderarray = [nsarray alloc];

swizzleinstancemethod([placeholderarray class], @selector(initwithobjects:count:), @selector(swizzle_initwithobjects:count:));

複製**

不止nsarray,在foundation中這樣的類簇還有nsdictionarynsstringnsnumber,所以如果想hook這些型別的方法,就要注意源方法實際屬於哪個子型別上。

OC中的類簇

類簇 class cluster 是一種設計模式,在foundation framework中被廣泛使用,舉個簡單的例子 nsarray arr nsarray arraywithobjects foo bar nil nslog arr class arr class output nsarray...

類簇的設計

這兒為了驗證xcode上類簇nsnumber實現過程設計了乙個簡化版類簇lonumber import inte ce lonumber nsobject property readonly int intvalue 獲取物件對應的 int資料 property readonly bool bool...

Foundation框架下的常用類

欄位的許可權 注 在類中宣告字段,可以為字段新增許可權 private 私有許可權 protected 保護許可權 public 公有許可權 inte ce father nsobject end father d 9 保護成員,被繼承了,仍然是保護成員 公有成員,被繼承了,仍然是公有成員 注 實際...