Cocoa绑定到数组中的单个对象

时间:2010-01-18 23:18:17

标签: cocoa cocoa-bindings key-value-observing nsarraycontroller key-value-coding

我之前发布过这个问题是对相关主题的评论,认为这很简单。那个帖子在这里:

Cocoa binding to a particular item in an array controller

这些问题与我正在构建的游戏有关(我将在这里更全面地描述),以尝试和学习Objective-c和cocoa。它足以让人想到它像德州扑克一样。一台服务器保存游戏信息并管理来自可变数量的客户端(总是多于一个)的输入。通过可可绑定,它向每个玩家显示使用IB中的阵列控制器存储在服务器上的阵列中的游戏的公共信息。可以想象桌面上的五张卡存储在服务器上的NSArray中,并绑定到每个客户端的NSArrayController的内容字段。

这部分工作得很好,就像一个魅力。但是,每个玩家都有两张他需要保密的牌。每个客户端应根据发给特定玩家的内容显示不同的卡。 (因为真正发生的事情是我绑定了一系列玩家对象

NSArray * thePlayers, 

想象所有的卡都存储在同一个阵列上)。所以我的问题是,如何从阵列控制器中设置绑定到单个对象(或者我需要一些其他控制器)?也就是说,如何绑定到thePlayers数组的一个玩家?'

3 个答案:

答案 0 :(得分:4)

您在控制器或模型中设置属性以访问该特定播放器并绑定到该属性。无法直接绑定到数组中特定索引处的对象。

答案 1 :(得分:2)

如果您确实要绑定到特定的数组索引,则可以创建包装器对象。像这样的东西。它允许您绑定到item0item1等等。没有范围检查,如果你改变了数组的大小就会中断,但你明白了。

接口

@interface MyArrayBinder : NSObject {
    NSMutableArray *array;
}
- (id)initWithMutableArray:(NSMutableArray *)theArray;
- (NSMutableArray *)array;
@end

实施

#include <objc/runtime.h>

static NSInteger _indexFromSelector(SEL sel) {
    return [[NSStringFromSelector(sel) stringByTrimmingCharactersInSet:[NSCharacterSet letterCharacterSet]] integerValue];
}

static void _dynamicSetItem(MyArrayBinder *self, SEL sel, id obj) {
    [self.array replaceObjectAtIndex:_indexFromSelector(sel) withObject:obj];
}

static id _dynamicItem(MyArrayBinder *self, SEL sel)  {
    return [self.array objectAtIndex:_indexFromSelector(sel)];
}

@implementation MyArrayBinder

- (id)initWithMutableArray:(NSMutableArray *)theArray {
    self=[super init];
    if (self) {
        array=theArray;
        for(NSUInteger i=0; i<[array count]; i++) {
            class_addMethod([self class], NSSelectorFromString([NSString stringWithFormat:@"item%lu", i]), (IMP) _dynamicItem, "@@:");  
            class_addMethod([self class], NSSelectorFromString([NSString stringWithFormat:@"setItem%lu:", i]), (IMP) _dynamicSetItem, "v@:@");  
        }       
    }
    return self;
}

- (NSMutableArray *)array {
    return array;
}

@end

答案 2 :(得分:1)

  

然而,每个玩家都有两张他需要保密的牌。每个客户端应根据发给特定玩家的内容显示不同的卡。 (因为真正发生的事情是我绑定了一系列玩家对象......

客户知道它代表哪个玩家,对吧?不是索引 - 它应该直接引用坐在键盘上的玩家的Player对象。像MyPlayer *userPlayer;这样的东西。除了持有所有玩家阵列的经销商对象之外,还包括那个。

一旦你有这样的方式,客户端控制器有一个属性,其值是用户的Player对象,绑定变得简单:你将卡视图直接绑定到{A的卡A和卡B 1}}客户端控制器的属性。 (这基本上是Chuck在他的回答中提出的建议,以及我在你对另一个问题的答案的评论中提出的建议。)

  

想象所有的卡都存储在同一个阵列上。

为什么我要想象?为什么玩家不单独拥有自己的牌?

好的,所以经销商应该拥有所有的牌(即牌组)。它应该共同拥有玩家持有的那些。玩家不通过经销商访问他们的卡;每个玩家都应该直接持有他们的牌。

听起来你用卡片和玩家犯了同样的错误:认为一个对象可以/应该通过索引通过数组知道另一个对象。如果你想在Bindings中使用这些知识,你肯定不会 - 但不应该。一个对象需要直接知道另一个 。这不仅是正确的解决方案,也是对象相互了解的正确方法。任何基于数组索引的引用都会更复杂,没有任何好处。