5

當更新基礎數組的方法被調用時,我需要做什麼來更新綁定到NSArrayController的tableView?一個例子可能會澄清這一點。NSArrayController和KVO

當我的應用程序啓動時,它會創建一個SubwayTrain。當SubwayTrain初始化時,它會創建一個SubwayCar。 SubwayCar有一個可變數組'乘客'。當一輛地鐵車輛被初始化時,乘客陣列被創建,並且放入一些People對象(比如說一個名爲「收票員」的人和一個名爲「無家可歸的人」的人)。這些人總是在SubwayCar上,所以我在初始化時創建它們並將它們添加到乘客陣列中。

在應用程序的生命中,人們登上汽車。在SubwayCar上調用addPassenger,並將其作爲參數傳入。

我有一個NSArrayController綁定到subwayTrain.subwayCar.passengers,並在推出時,我的門票收藏家和無家可歸的人顯示罰款。但是當我使用[subwayCar addPassenger:]時,tableView不會更新。我已經確認,乘客肯定會加入陣列,但沒有更新的gui。

我可能會做錯什麼?我的直覺是它與KVO相關 - 當addPassenger被調用時,數組控制器不知道更新(即使addPassenger調用[passengers addObject:]。我在這裏會發生什麼錯誤 - 如果它有幫助,我可以發佈代碼。

由於任何人願意幫忙。

UPDATE

所以,事實證明我能得到這個由addPassenger方法改變從

[seatedPlayers addObject:person]; 

工作

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers]; 

[newSeatedPlayers addObject:sp]; 

[seatedPlayers release]; 

[self setSeatedPlayers:newSeatedPlayers]; 

我想這是因爲我正在使用[self setSeatedPlayers]。這是做到這一點的正確方法嗎?複製數組,複製舊數據並更新副本(而不是僅添加到現有數組)似乎非常麻煩。

+0

如何將表視圖綁定到控制器?你有沒有將每個表列綁定到'subwayTrain.subwayCar.passengers'屬性(例如,列名綁定到'subwayTrain.subwayCar.passengers.name')? – outis 2010-01-15 03:59:50

+0

是的。旅客名單在啓動時顯示。 – 2010-01-15 04:32:30

回答

1

所以,事實證明我能得到這個由addPassenger方法改變從

[seatedPlayers addObject:person]; 

工作

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers]; 
[newSeatedPlayers addObject:sp]; 
[seatedPlayers release]; 
[self setSeatedPlayers:newSeatedPlayers]; 

我想這是因爲我使用[self setSeatedPlayers]。這是做到這一點的正確方法嗎?

首先,它是setSeatedPlayers:,與冒號。這在Objective-C中非常重要。

使用你自己的setter是正確的方法,但是你使用了錯誤的正確方法。它可以工作,但是你仍然在編寫比你需要的更多的代碼。

你應該做的是實現set訪問器,如addSeatedPlayersObject:。然後,發送自己的消息。這使得加人短的一行:

[self addSeatedPlayersObject:person]; 

而且只要你遵循the KVC-compliant accessor formats,你會得到免費的志願通知,就像你做setSeatedPlayers:

的這種過度setSeatedPlayers:的優點是:

  • 您的代碼變異的設置會更短。
  • 因爲它更短,它會更乾淨。
  • 使用特定的set-mutation訪問器提供了特定的set-mutation KVO通知的可能性,而不是一般的整個dang-set-changed通知。

我也比較喜歡這個解決方案而不是mutableSetValueForKey:,這是爲了簡潔起見,也是因爲它很容易拼錯那個字符串的關鍵字。 (Uli Kusterer has a macro to cause a warning when that happens,當你真的需要跟KVC或志願本身,這是非常有用的。)

7

我不知道它是否考慮了一個bug,但是addObject :(和removeObject:atIndex :)不會生成KVO通知,這就是爲什麼數組控制器/表視圖沒有得到更新。爲了符合國際志願者組織-,使用mutableArrayValueForKey:

例子:

[[self mutableArrayValueForKey:@"seatedPlayers"] addObject:person]; 

你也想實現insertObject:inSeatedPlayersAtIndex:因爲默認志願的方法是很慢的(他們創造了一個全新的陣列,加該對象到數組,並將原來的陣列到新陣列 - 非常低效)

- (void)insertObject:(id)object inSeatedPlayerAtIndex:(int)index 
{ 
    [seatedPlayers insertObject:object atIndex:index]; 
} 

注意,當陣列控制器的對象添加這個方法也將被調用,所以它也是一個漂亮的勾手想了想比如註冊撤銷操作等等

1

我還沒有試過這個,所以我不能說,它的工作原理,但不會通過調用

insertObject得到志願通知:atArrangedObjectIndex:

在ArrayController?

+0

是的,使用NSArrayController對數組進行變異使得NSArrayController知道變異,並且它(和與之相關的東西)應該相應地更新。 – ipmcc 2012-12-03 19:20:34

0
  1. 使用willChangeValueForKey:didChangeValueForKey:纏的成員發生變化時的變化似乎並沒有引起KVO通知。這在您直接更改實例變量時派上用場。

  2. 使用willChangeValueForKey:withSetMutation:usingObjects:didChangeValueForKey:withSetMutation:usingObjects:在變更看起來不會導致KVO通知時,會環繞集合內容的更改。

  3. 使用[seatedPlayers setByAddingObject:sp]可以縮短事物並避免不必要地分配可變集。

總體而言,我願意做任一此:

[self willChangeValueForKey:@"seatedPlayers" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:sp]; 
[seatedPlayers addObject:sp]; 
[self didChangeValueForKey:@"seatedPlayers" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:sp]; 

或該:

[self setSeatedPlayers:[seatedPlayers setByAddingObject:sp]]; 

與後者的替代造成的下1.第一替代列出的功能的自動調用應該表現更好。

1

Key Value Observing的關鍵是在Key Value Compliance。您最初使用的方法名爲addObject:它只與「無序訪問器模式」關聯,而您的屬性是索引屬性(NSMutableArray)。當您將您的屬性更改爲無序屬性(NSMutableSet)時,它就起作用了。考慮將NSArray或NSMutableArray作爲索引屬性,將NSSet或NSMutableSet作爲無序屬性。你真的必須仔細閱讀這一部分,以瞭解什麼是使魔法發生所必需的...... Key-Value-Compliance。即使您不打算使用它們,也有一些針對不同類別的「必需」方法。