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。即使您不打算使用它们,也有一些针对不同类别的“必需”方法。