如何将对象添加到以编程方式绑定的NSMutableArray?

问题描述 投票:1回答:4

我有一个具有以下结构的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方法中的对象添加到MyView myViewArray时,它们似乎没有更新MyDocument的myArray。我已经尝试了以下两种方法:

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

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

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

objective-c cocoa cocoa-bindings key-value-observing key-value-coding
4个回答
1
投票

问题是您要直接更改数组。实施indexed accessor methods并调用它们。

KVO会覆盖您的访问器方法(只要您符合certain formats)并发布必要的通知。直接与数组对话时,您不会得到此信息。除非明确告知,否则绑定到该属性的所有内容都不知道您已经更改了该属性。当您使用访问器方法时,KVO会为您告诉其他对象。

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

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

  • 视图在更改其属性时,将自动通知数组控制器,该控制器将更改其content属性,并通知您的控制器。
  • 您的控制器在更改其属性时将自动通知数组控制器,该控制器将更改其arrangedObjects属性,该属性将通知视图。

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声明为MyView中的属性?它应该看起来像这样:

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

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

    update:如何使用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
      

      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的各种属性,我欢迎对此答案发表评论。谢谢。


      1
      投票

      首先,绑定到ArrangedObjects并没有什么问题:例如,一个NSTableColumn的内容应仅绑定到ArrangedObjects,而其contentValues则应与ArrangedObjects.someProperty绑定。

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

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

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

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

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

      [self.myArrayController addObject: anObject]
      
      © www.soinside.com 2019 - 2024. All rights reserved.