代码之家  ›  专栏  ›  技术社区  ›  Ben Packard Ross Knipe

NSarraycontroller和kvo

  •  5
  • Ben Packard Ross Knipe  · 技术社区  · 16 年前

    当调用更新基础数组的方法时,我需要做什么来更新绑定到NSarrayController的TableView?一个例子可以澄清这一点。

    当我的应用程序启动时,它会创建一个子高速公路。当子高速公路初始化时,它会创建一个单独的子高速公路。亚高速汽车有一个可变的“乘客”阵列。当地铁车辆初始化时,创建乘客数组,并放入几个人对象(例如,名为“收票人”的人和另一个名为“无家可归的人”)。这些家伙总是在子高速公路上,所以我在初始化时创建它们,并将它们添加到乘客数组中。

    在应用程序使用期间,人们登上汽车。”“addpassenger”在子付费汽车上被调用,作为参数传入。

    我有一个NSarraycontroller绑定到了subwaytrain.subwaytcar.passengers,在启动时,我的收票员和无家可归的人都很好地出现了。但是当我使用[SubwayCarAddPassenger:]时,TableView不会更新。我已经确认乘客肯定被添加到了阵列中,但是在GUI中没有任何更新。

    我可能做错什么了?我的直觉是,它与kvo相关——阵列控制器不知道何时调用addpassenger(即使addpassenger调用[passengers addobject:])进行更新。我在这里可能出了什么问题-如果有帮助,我可以发布代码。

    感谢任何愿意帮忙的人。

    更新

    所以,我可以通过addpassenger方法从

    [seatedPlayers addObject:person];
    

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

    我想这是因为我正在使用[自设置的播放机]。这是正确的方法吗?复制数组、释放旧数组和更新副本(而不仅仅是添加到现有数组)看起来非常麻烦。

    5 回复  |  直到 16 年前
        1
  •  1
  •   Peter Hosey    16 年前

    所以,我可以通过addpassenger方法从

    [seatedPlayers addObject:person];
    

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

    我想这是因为我在使用 [self setSeatedPlayers] . 这是正确的方法吗?

    首先,它是 setSeatedPlayers: 和结肠。这在目标C中至关重要。

    使用自己的setter是正确的方法,但使用的方法不正确。它可以工作,但是你写的代码仍然比你需要的要多。

    您应该做的是实现set访问器,例如 addSeatedPlayersObject: . 然后,给自己发这个信息。这使添加人员成为一个简短的一行:

    [self addSeatedPlayersObject:person];
    

    只要你跟着 the KVC-compliant accessor formats ,您将免费获得kvo通知,就像您使用 设置已设置的播放机: .

    这比 设置已设置的播放机: 是:

    • 要改变集合的代码将更短。
    • 因为它比较短,所以会更干净。
    • 使用特定的set mutation访问器可以提供特定的set mutation kvo通知,而不是一般的整个dang set changed通知。

    我也更喜欢这个解决方案 mutableSetValueForKey: ,既为了简洁,也因为很容易将键拼写为字符串文字。( Uli Kusterer has a macro to cause a warning when that happens ,这在您确实需要与kvc或kvo本身对话时非常有用。)

        2
  •  7
  •   Saurabh Sharan    16 年前

    我不知道它是否被视为bug,但是addobject:(和removeobject:atindex:)不生成kvo通知,这就是为什么数组控制器/表视图没有得到更新的原因。要符合kvo,请使用mutableArrayValueForkey:

    例子:

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

    您还需要实现insertObject:insatedplayersatindex:因为默认的kvo方法非常慢(它们创建了一个全新的数组,将对象添加到该数组,并将原始数组设置为新的数组--效率非常低)

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

    注意,当数组控制器添加对象时也会调用这个方法,因此它也是一个很好的钩子,可以考虑注册一个撤消操作等。

        3
  •  1
  •   Lennart Bonnevier    16 年前

    我没有试过,所以我不能说它有效,但是你不会通过打电话得到kvo通知吗?

    插入对象:AtarrangedObjectIndex:

    在阵列控制器上?

        4
  •  1
  •   Samuel    13 年前

    神奇的钥匙 Key Value Observing 是在 Key Value Compliance . 您最初使用的方法名为addObject:它只与“无序访问器模式”关联,而您的属性是一个索引属性(nsmutableArray)。当您将属性更改为无序属性(nsmutableset)时,它起作用。将nsarray或nsmutablearray视为索引属性,nsset或nsmutableset视为无序属性。你真的必须仔细阅读这一部分,以知道什么是必须的,使魔术发生… Key-Value-Compliance .对于不同的类别有一些“必需”的方法,即使您不打算使用它们。

        5
  •  0
  •   Ivan Vučica    14 年前
    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下面列出的函数。第一选择 应该 表现得更好。