1

我之前将此问题发布为对相关线程的评论,认为这很简单。该线程在这里:

Cocoa 绑定到数组控制器中的特定项目

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

这部分工作正常,就像一个魅力。但是,每个玩家都有两张需要保密的牌。每个客户应该根据发给特定玩家的牌显示不同的牌。(因为真正发生的是我绑定到一组玩家对象

NSArray * thePlayers, 

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

4

4 回答 4

4

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

于 2010-01-18T23:32:02.440 回答
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
于 2011-02-02T14:15:56.297 回答
1

但是,每个玩家都有两张需要保密的牌。每个客户应该根据发给特定玩家的牌显示不同的牌。(因为真正发生的是我绑定到一组玩家对象……</p>

客户知道它代表的是哪个玩家,对吧?不是按索引——它应该对坐在键盘前的玩家直接引用 Player 对象。类似的东西MyPlayer *userPlayer;这是对包含所有玩家数组的庄家对象的补充,包括那个玩家。

一旦你以这种方式布局,客户端控制器的属性值是用户的 Player 对象,绑定就变得简单了:你将卡片视图直接绑定到userPlayer客户端控制器属性的卡片 A 和卡片 B . (这基本上是查克在他的回答中已经提出的建议,以及我在我对你对另一个问题的回答的评论中提出的建议。)

想象所有卡片都存储在同一个数组中)。

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

好的,所以庄家应该拥有所有的牌(即牌组)。它应该共同拥有玩家也持有的那些。玩家不通过庄家访问他们的牌;每个玩家应该直接持有他或她的牌。

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

于 2010-01-19T06:06:58.710 回答
0

与尼克摩尔的解决方案非常相似:

如果您确实想绑定到特定的数组索引,您可以创建一个包装器对象。像这样的东西。它允许您绑定到 item0、item1 等。没有范围检查,如果您更改数组的大小,它会中断,但您明白了。

界面

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

执行

static NSInteger _indexFromString(NSString *key) {
    return [[key stringByTrimmingCharactersInSet:[NSCharacterSet letterCharacterSet]] integerValue];
}

@implementation MyArrayBinder

- (id)initWithMutableArray:(NSMutableArray *)theArray {
    if ( self=[super init] ) {
        _array=theArray;
    }
    return self;
}

- (id)valueForUndefinedKey:(NSString *)key {
    return _array[_indexFromString( key )];
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
    _array[_indexFromString( key )] = value;
}

@end
于 2022-02-12T13:28:04.977 回答