從NSArray看類簇

2021-07-26 23:46:45 字數 2685 閱讀 1084

class clusters(類簇)是抽象工廠模式在ios下的一種實現,眾多常用類,如nsstringnsarraynsdictionarynsnumber都運作在這一模式下,它是介面簡單性和擴充套件性的權衡體現,在我們完全不知情的情況下,偷偷隱藏了很多具體的實現類,只暴露出簡單的介面。

熟悉這個模式的同學很可能看過下面的測試**,將原有的alloc+init拆開寫:

id obj1 = [nsarray alloc]; // __nsplacehodlerarray *

id obj2 = [nsmutablearray alloc]; // __nsplacehodlerarray *

id obj3 = [obj1 init]; // __nsarrayi *

id obj4 = [obj2 init]; // __nsarraym *

發現+ alloc後並非生成了我們期望的類例項,而是乙個__nsplacehodlerarray的中間物件,後面的- init- initwith***xx訊息都是傳送給這個中間物件,再由它做工廠,生成真的物件。這裡的__nsarrayi__nsarraym分別對應immutable和mutable(後面的i和m的意思)

於是順著思路猜實現,__nsplacehodlerarray必定用某種方式儲存了它是由誰alloc出來的這個資訊,才能在init的時候知道要建立的是可變陣列還是不可變陣列

於是乎很開心的去看了下*obj1的記憶體布局:

下面是32位模擬器中的記憶體布局(64位太長不好看就臨時改32位了- -),第乙個箭頭是*obj1,第二個是*obj2

我們知道,物件的前4位元組(32位下)為isa指標,指向類物件位址,上圖所示的0x0051e768就是__nsplacehodlerarray類物件位址,可以從lldb下po這個位址來驗證。

那麼問題來了,這個中間物件並沒有儲存任何資訊誒(除了isa外就都是0了),那它init的時候咋知道該建立什麼呢?

經過研究發現,foundation用了乙個很賤的比較靜態例項位址方式來實現,偽**如下:

static __nsplacehodlerarray *getplaceholderfornsarray() 

return instancefornsarray;

}static __nsplacehodlerarray *getplaceholderfornsmutablearray()

return instancefornsmutablearray;

}// nsarray實現

+ (id)alloc

}// nsmutablearray實現

+ (id)alloc

}// __nsplacehodlerarray實現

- (id)init

else

if (self == getplaceholderfornsmutablearray())

return

self;

}

foundation不是開源的,所以上面的**是猜測的,思路大概就是這樣,可以這樣驗證下:

id obj1 = [nsarray alloc];

id obj2 = [nsarray alloc];

id obj3 = [nsmutablearray alloc];

id obj4 = [nsmutablearray alloc];

// 1和2位址相同,3和4位址相同,無論多少次都相同,且位址相差16位

除此之外,foundation對不可變版本的空陣列也做了個小優化:

nsarray *arr1 = [[nsarray alloc] init];

nsarray *arr2 = [[nsarray alloc] init];

nsarray *arr3 = @;

nsarray *arr4 = @;

nsarray *arr5 = @[@1];

上邊1-4號都指向了同乙個物件,而arr5指向了另乙個物件。

若干個不可變的空陣列間沒有任何特異性,返回乙個靜態物件也理所應當。

不僅是nsarray,foundation中如nsstring,nsdictionary,nsset等區分可變和不可變版本的類,空例項都是靜態物件(nsstring的空例項物件是常量區的@""

所以也給用這些方法來測試物件記憶體管理的同學提個醒,很容易意料之外的。

NSArray類方法整理

創 建 nsinteger len1 arr11 count nsarray array1 qian feng world 版本新增方法 nsarray array2 nsarray alloc initwitharray array1 nsarray array3 nsarray alloc in...

從類記憶體看虛表

結合文章看 情形一 單繼承,派生類中只有乙個虛表 include stdafx.h using namespace std include 基類a 單繼承中我們可以看出,派生類中只有乙個虛表,是從基類繼承過來的虛表,基類的虛表裡的內容先儲存到虛表中,接著如果派生類重寫了基類的虛函式則重新覆蓋更新基類...

類簇的設計

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