2010-06-06 57 views
2

我有一個只讀屬性,我試圖實現NSCopying的對象。它有一個名爲「subConditions」(其中包含「SubCondition」對象)的mutableArray。我讓它只讀,因爲我希望調用者能夠更改數組中的數據,而不是數組本身。在編寫-copyWithZone:方法之前,這一切都非常有效。正確的方法來複制只讀NSMutableArray

經過一番摸索之後,我設法得到了一些似乎可行的東西。我不確定這是否是最佳做法。這裏是我的-copyWithZone:方法的簡化版本:

-(id)copyWithZone:(NSZone*)zone 
{ 
    Condition *copy = [[[self class]allocWithZone:zone]init]; 


NSArray *copiedArray = [[NSArray alloc]initWithArray:self.subConditions copyItems:YES]; 
[copy.subConditions setArray:copiedArray]; 
[copiedArray release]; 

    return copy; 
} 

這是複製readonly mutableArray的正確方法/最佳方法嗎?

回答

2

我已經使[可變數組屬性]只讀,因爲我想調用者能夠更改數組中的數據,但不是數組本身。

在不知情的情況下變更對象屬性的值就是錯誤的mojo。作爲一個例子,假設對象有一個索引集,通過它來知道哪些對象被選中;如果另一個對象從數組中刪除了一些子條件,則該集合中的部分或全部索引可能會引用錯誤的對象或根本沒有對象,這意味着訪問選定的子條件將導致NSOutOfRangeException。

這是一個壞習慣,解決的辦法是切換到逆向習慣,即永遠不要這樣做。通過告訴它的所有者進行更改 - 或者至少使用所應用的更改創建自己的陣列,並將其顯示給原始陣列的所有者,從而更改擁有的陣列。在後一種解決方案中,所有者(條件)可能會消除其索引集並忘記選擇,但這還是比引發異常更好。

將屬性的類型從NSMutableArray更改爲NSArray後,上面的代碼應該會發出警告,因爲只有NSMutableArrays纔會響應setArray:。 (該代碼仍將工作,假設subConditions訪問器返回可變數組而不是自動釋放副本,但編譯器會給出關於它的警告。)通過將數組從表中突變,問題變爲如何啓用條件類提供一個Condition實例的副本,並複製一個複製的子條件數組,但不允許其他類執行此操作。

一種解決方案是將新數組直接存儲到副本的實例變量中。通常情況下,這也是不好的魔咒,但在這個特定的上下文中(copyWithZone:,受影響的對象是副本),這是適合的極少數情況之一。使用指針到成員運營商這樣做:

copy->subConditions = [[NSMutableArray alloc]initWithArray:self.subConditions copyItems:YES]; 

另一個解決辦法是使用class extension的財產重新申報的類的實現文件中readwrite。 (請在類的頭文件readonly聲明。)然後你可以使用屬性訪問消息:

copy.subConditions = [[[NSArray alloc]initWithArray:self.subConditions copyItems:YES]autorelease]; 

沒有太多推薦了另一種,除了直接伊娃訪問速度稍快:該物業版本創建一個臨時數組,併發送訪問者消息以使新條件創建該數組的副本。您可能首先要使用屬性訪問版本,然後使用工具來分析您的應用程序,以確定您關心的硬件上的開銷是否很重要。

+0

謝謝你非常詳盡的解釋! – 2010-06-06 13:35:30

+0

「因爲只有NSMutableArrays響應setArray:」NSMutableArrays不迴應這種事 – user102008 2011-01-20 23:47:27

+1

@ user102008:是的,他們這樣做。 http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html%23//apple_ref/occ/instm/NSMutableArray/setArray%3A – 2011-01-21 04:17:17

相關問題