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 のメソッドのオブジェクトを MyView に追加しようとすると、 MyDocumentmyViewArraymyArray. 次の両方のアプローチを試しました。

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

(2 番目のアプローチでは、予想どおりコンパイラ エラーが発生しますが、KVO に関する私の限られた理解により、Objective-C ランタイムはこのメソッドを「実装」すると考えていました。)

更新しようとしている方法に何か問題がありますmyViewArrayか? プログラムによるバインドに何か問題がありますか? (MyView はカスタム ビューであり、IB パレットを作成したくないため、プログラムでこれを実行しようとしています。)

4

4 に答える 4

1

問題は、MyViewをそのプロパティではなくmyViewArrayNSArrayControllerのarrangedObjectsプロパティにバインドしていたことのようcontentです。

にバインドすると、が指す実際のオブジェクトがのインスタンスであるarrangedObjectsことがわかりました。オンラインで詳細を検索したところ、このオブジェクトが実際に何をするのかについての明確な答えは見つかりませんでした。ただし、私が見つけたコード例は、NSControllerArrayProxyが、(配列内の)オブジェクト自体ではなく、配列内のオブジェクトのプロパティにアクセスするための便利さを公開することを目的としていることを示唆しています。これが、私がにバインドするのを間違えたと私が信じる理由です。myViewArrayNSControllerArrayProxyarrangedObjects

解決策は、代わりにMyViewmyViewArrayを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

ここで 2 つの可能性を確認できます。

まず、クラス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
    

    それ以外は、すべてのバインディングを適切に行っているように見えます。

    更新: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

      問題は、配列を直接変更していることです。インデックス付きのアクセサー メソッドを実装し、それらを呼び出します。

      KVO は、(特定の形式に準拠している限り) アクセサー メソッドをオーバーライドし、必要な通知を投稿します。配列と直接対話する場合、これは得られません。プロパティにバインドされているものは、明示的に伝えない限り、プロパティが変更されたことを認識しません。アクセサー メソッドを使用すると、KVO が他のオブジェクトに通知します。

      アクセサ メソッド (合成されたものであろうとなかろうと) を使用しない唯一の時間はinitandです。deallocinitdealloc

      独自のアクセサ メソッドを使用して配列を変更し、それによって無料の KVO 通知を取得すると、次のように動作するはずです。

      • ビューは、そのプロパティを変更すると、配列コントローラーに自動的に通知し、そのcontentプロパティが変更され、コントローラーに通知されます。
      • コントローラーは、そのプロパティを変更すると、配列コントローラーに自動的に通知し、配列コントローラーはそのarrangedObjectsプロパティを変更し、ビューに通知します。
      于 2009-04-17T19:51:10.207 に答える
      1

      まず第一に、arrangedObjects へのバインドに問題はありません。たとえば、NSTableColumn は、そのコンテンツを ArrangedObjects のみにバインドし、その contentValues を ArrangedObjects.someProperty にバインドする必要があります。

      よくある間違いは、arrangedObjects を arrayController のコンテンツとみなすことですが、これまで見てきたように、それは悲惨な結果を招くことになります。arrangedObjects は、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 に答える