第10條 在既有類中使用關聯物件存放自定義資料

2022-03-25 22:28:56 字數 2474 閱讀 6632

本條要點:(作者總結)

有時需要在物件中存放相關資訊。這時我們通常從物件所屬的類中繼承乙個子類,然後改用這個子類物件。然而並非所有情況下都能這麼做,有時候類的例項可能是由某種機制所建立的,而開發者無法令這種機制建立出自己所寫的子類例項。objective-c 中有一項強大的特性可以解決此問題,這就是「關聯物件」(associated object)。

可以給某物件關聯許多其他物件,這些物件通過「鍵」來區分。儲存物件值的時候,可以指明「儲存策略」(storage policy),用以維護相應的「記憶體管理語義」。儲存策略由名為 objc_associationpolicy 的列舉所定義,下表列出了該列舉的取值,同時還列出了與之等效的 @property 屬性:假如關聯物件成為了屬性,那麼它就會具備對應的語義:

物件關聯型別

關聯型別

等效的@property 屬性

objc_association_assign

assign

objc_association_retain_nonatomic

nonatomic, retain

objc_association_copy_nonatomic

nonatomic,copy

objc_association_retain

retain

objc_association_copy

copy

下列方法可以管理關聯物件:

我們可以把某物件想象成 nsdidctionary,把關聯到該物件的值理解為字典中的條目,於是,訪問關聯物件的值就相當於在 nsdictionary 物件上呼叫[object setobject:value forkey:key]與 [object objectforkey:key]方法。然而兩者之間有個重要差別:設定關聯物件時用的鍵(key)是個「不透明的指標」(opaque pointer)(其所指向的資料結構不侷限於某種特定型別的指標)。如果在兩個鍵上呼叫 「isequel:」方法的返回值是 yes,那麼 nsdictionary 就認為二者相等;然而在設定關聯物件值時,若想令兩個鍵匹配到同乙個值,則二著必須是完全相同的指標才行。鑑於此,在設定關聯物件值時,通常使用靜態全域性變數做鍵。

開發ios 時經常用到 uialertview 類,該類提供了一種標準檢視,可向使用者展示警告資訊。當使用者按下按鈕關閉該檢視時,需要用委託協議(delegate protocol)來處理此動作,但是,要想設定好這個委託機制,就得把建立警告檢視和處理按鈕動作的**分開。由於**分作兩塊,所以讀起來有點亂。比方說,我們在使用 uialertview 時,一般都會這麼寫:

1 - (void

)askuseraquestion 56

//uialertviewdelegate protocol method

7 - (void)alertview:(uialertview *)alertview clickedbuttonatindex:(nsinteger)buttonindex else

13 }

如果想在同乙個類裡處理多個警告資訊檢視,那麼**就會變的更為複雜,我們必須在 delegate 方法中檢查傳入的 alertview 引數,並據此選用相應的邏輯。要是能在建立警告檢視的時候直接把處理每個按鈕的邏輯都寫好,那就簡單多了。這可以通過關聯物件來做。建立完警告檢視之後,設定乙個與之關聯的 「快」(block),等到執行 delegate 方法時再將其讀出來。此方案的實現**如下:

1

static

void *eocmyalertviewkey = "

eocmyalertviewkey";

2 - (void

)askuseraquestion else

10};

1112

objc_setassociatedobject(alert, eocmyalertviewkey, block, objc_association_copy);

13[alert show];14}

1516 - (void)alertview:(uialertview *)alertview clickedbuttonatindex:(nsinteger)buttonindex

以這種方式改寫之後,建立警告檢視與處理操作結果的**都放在一起了,這樣比原來更易讀懂,因為我們無須在兩部分**之間來回遊走,即可明白警告檢視的用處。但是,採用該方案時需注意:塊可能要捕獲(capture)某些變數,這也許會造成「保留環」(retain cycle)。

正如大家所見,這種做法很有用,但是只應該在其他辦法行不通時才去考慮它,若是濫用,則很快就會令**失控,使其難於除錯。「保留環」產生的原因很難查明,因為關聯物件之間的關係並沒有正式的定義(formal definition),其記憶體管理語義是在關聯的時候才定義的,而不是在介面中預先定好的。使用這種寫法時要小心,不能僅僅因為某處可以用該方法就一定要用它。想建立這種 uialertview 還有個辦法,那就是從中繼承子類,把塊儲存為子類中的屬性。筆者認為:若是需要多次使用到 alert 檢視,那麼這種做法比關聯物件要好。

end

在既有類中使用關聯物件存放自定義資料

有時需要在物件中存放相關資訊。這時我們通常會從物件所屬的類中繼承乙個子類,然後改用這個子類物件。然而並非所有情況下都能這麼做,有時候類的例項可能是由某種機制所建立的,而開發者無法令這種機制建立出自己所寫的子類例項。objective c中有一項強大的特性可以解決此問題,這就是 關聯物件 associ...

在ASP中使用類

vbscript5中增加了許多新功能,最振奮人心的當屬類和正規表示式的出現。以下是本人寫的乙個解析html 的類。我是 學php的,語法有不習慣的地方,請大家多包含。class htmlparse 設定 initialize 事件。private sub class initialize myglo...

第14條 在公有類中使用訪問 方法而非公有域

class point 如上面point類的資料域是可以直接被訪問的,這樣的類沒有提供封裝。如果不改變api,就無法改變它的資料表示法 比如,使用乙個比double更高精度的類來表示x和y 也無法強加任何約束條件 比如以後我們可能會希望x和y不會超過某個值 class point public do...