1

我有一个具有以下结构的 NSDocument:

@interface MyDocument : NSDocument
{
    NSMutableArray *myArray;

    IBOutlet NSArrayController *myArrayController;
    IBOutlet MyView *myView;
}
@end

我在 MyDocument.xib 中实例化了 NSArrayController 和 MyView,并与文件的所有者 (MyDocument) 建立了连接,所以我很确定从 Interface Builder 的角度来看,我已经正确地完成了所有操作。

MyView 的界面很简单:

@interface MyView : NSView {
    NSMutableArray *myViewArray;
}
@end

现在,在 中MyDocument windowControllerDidLoadNib,我有以下代码:

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];
    [myArrayController setContent:myArray];
// (This is another way to do it)    [myArrayController bind:@"contentArray" toObject:self withKeyPath:@"myArray" options:nil];

    [myView bind:@"myViewArray" toObject:myArrayController withKeyPath:@"arrangedObjects" options:nil];
}

在调试器中,我已经验证了它myViewArray是一个 NSControllerArrayProxy,所以看起来我的编程绑定是正确的。但是,当我尝试将 MyView 方法中的对象添加到 MyViewmyViewArray时,它们似乎不会更新 MyDocument 的myArray. 我尝试了以下两种方法:

[myViewArray addObject:value];
[self addMyViewArraysObject:value];

(正如预期的那样,第二种方法会导致编译器错误,但我认为根据我对 KVO 的有限理解,Objective-C 运行时会“实现”此方法。)

我尝试更新的方式有问题myViewArray吗?我的编程绑定有问题吗?(我正在尝试以编程方式执行此操作,因为 MyView 是自定义视图,我不想为其创建 IB 调色板。)

4

4 回答 4

1

我可以在这里看到两种可能性:

首先,您是否NSMutableArray在您的类中实例化该对象(并释放它)MyDocument?它应该看起来像这样:

- (id)init
{
    if ((self = [super init]) == nil) { return nil; }
    myArray = [[NSMutableArray alloc] initWithCapacity:0];
    return self;
}

- (void)dealloc
{
    [myArray release];
    [super dealloc];
}

其次,您是否将 myViewArray 声明为 in 中的属性MyView?它应该看起来像这样:

// MyView.h:
@interface MyView : NSView
{
    NSMutableArray * myViewArray;
}
@property (assign) NSMutableArray * myViewArray;
@end
    // MyView.m:
    @implementation MyView
    
    @synthesize myViewArray;
    
    @end
    

    除此之外,在我看来,您已正确完成所有绑定。

    更新:如何使用NSArrayController将项目添加到数组:

    // MyView.h:
    @interface MyView : NSView
    {
        NSMutableArray * myViewArray;
        IBOutlet NSArrayController * arrayController;
    }
    @property (assign) NSMutableArray * myViewArray;
    - (void)someMethod;
    @end
    
      // MyView.m:
      @implementation MyView
      
      @synthesize myViewArray;
      
      - (void)someMethod
      {
          id someObject = [[SomeClass alloc] init];
          [arrayController addObject:[someObject autorelease]];
      }
      
      @end
      
      于 2009-04-17T13:46:02.817 回答
      1

      问题似乎是我一直将 MyView 绑定myViewArray到 NSArrayController 的arrangedObjects属性而不是它的content属性。

      绑定到 时arrangedObjects,我发现 指向的实际对象myViewArray是 的一个实例NSControllerArrayProxy。当我在网上搜索有关它的更多信息时,我没有找到关于该对象实际作用的明确答案。但是,我发现的代码示例表明 NSControllerArrayProxy 旨在公开访问数组中对象属性的便利,而不是对象(数组中)本身。这就是为什么我认为我错误地绑定到arrangedObjects.

      解决方案是将 MyView 绑定myViewArray到 NSArrayController 的content属性:

      - (void)windowControllerDidLoadNib:(NSWindowController *) aController
      {
          [super windowControllerDidLoadNib:aController];
      
          [myArrayController setContent:myArray];
          [myView bind:@"myViewArray" toObject:myArrayController withKeyPath:@"content" options:nil];
      }
      

      尽管这似乎可行,但我不能 100% 确定content在这种情况下绑定是正确的。如果有人可以对以编程方式绑定到 NSArrayController 的各种属性有所了解,我会欢迎对此答案发表评论。谢谢。

      于 2009-04-17T16:21:19.277 回答
      1

      问题是你直接改变你的数组。实现索引访问器方法并调用它们。

      KVO 会覆盖您的访问器方法(只要您符合某些格式)并发布必要的通知。当您直接与您的阵列交谈时,您不会得到这个;除非您明确告诉它,否则绑定到该属性的任何内容都不会知道您已更改该属性。当您使用访问器方法时,KVO 会告诉您其他对象。

      唯一不使用访问器方法(综合或其他)的时间是在initand中dealloc,因为您将与half init-ed 或dealloc-ked 对象交谈。

      一旦您使用自己的访问器方法来改变数组,从而获得免费的 KVO 通知,事情应该会正常工作:

      • 视图在改变它的属性时,会自动通知数组控制器,它改变它的content属性,通知你的控制器。
      • 你的控制器在改变它的属性时,会自动通知数组控制器,它改变它的arrangedObjects属性,通知视图。
      于 2009-04-17T19:51:10.207 回答
      1

      首先,绑定到排列对象没有任何问题:例如,一个 NSTableColumn 应该将其内容仅绑定到排列对象,并将其内容值绑定到排列对象.someProperty。

      常见的错误是将arrangerObjects 视为arrayController 的内容,但正如您所见,这会导致悲痛:arrangerObjects 是arrayController 当前在其内容中排列对象的方式的表示,而不是内容本身。

      也就是说,将数组绑定到 arrayController 的方法是:

      [self.myArrayController bind:NSContentArrayBinding 
       toObject:self
       withKeyPath:@"myView.myViewArray" 
       options:nil]; 
      

      顺便说一句,您确定您的视图需要保存 myViewArray 吗?这通常由控制器或模型对象负责。

      现在您可以通过在 arrayController调用 addObject 来添加对象,因为这是控制器的职责。

      [self.myArrayController addObject: anObject]
      
      于 2009-07-10T15:06:35.390 回答