1

У меня есть NSDocument, который имеет следующую структуру:Как добавить объект к программно связанному NSMutableArray?

@interface MyDocument : NSDocument 
{ 
    NSMutableArray *myArray; 

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

Я создание экземпляр NSArrayController и MyView в MyDocument.xib, и сделал подключение к файлу владелице (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]; 

(Второй подход вызывает ошибку компиляции, как и ожидался, но я думал, что во время выполнения Objective-C будет «реализовывать» этот метод за мое ограниченное понимание КВО.)

Есть ли что-то не так с тем, как я пытаюсь обновить myViewArray? Что-то не так с моей программной привязкой? (Я пытаюсь сделать это программно, поскольку MyView является настраиваемое представление, и я не хочу, чтобы создать палитру IB для него.)

ответ

1

Проблема в том, что вы непосредственно мутируете свой массив. Внесите indexed accessor methods и позвоните им.

KVO переопределяет ваши методы доступа (если вы соответствуете certain formats) и размещает необходимые уведомления. Вы не получаете этого, когда говорите напрямую с вашим массивом; все, связанное с этим свойством, не будет знать, что вы изменили свойство, если вы явно не указали его. Когда вы используете ваши методы доступа, KVO сообщает вам другие объекты.

Единственный раз, чтобы не использовать свои методы доступа (синтезированные или иным образом) в init и dealloc, так как вы будете говорить с половинным init ред или - dealloc keď объекта.

После того, как вы используете свои собственные методы доступа мутировать массив, и тем самым получать бесплатные уведомления Кво, все должно работать:

  • мнение, когда мутирует его свойство, автоматически уведомит массив контроллер, который мутирует его свойство content, которое уведомляет ваш контроллер.
  • Ваш контроллер при изменении его свойства автоматически уведомляет контроллер массива, который мутирует его свойство arrangedObjects, которое уведомляет представление.
+0

По какой-то причине я думал, что контроллер массива имеет некоторую способность слушать изменения в самом массиве. Я, возможно, все это сделал совершенно неправильно, потому что (как я ответил на ваш комментарий к моему ответу), даже если я добавлю insertObject: inMyViewArrayAtIndex: в MyView и попытаюсь вставить NSValue в myViewArray в этом методе и вызвать этот метод из mouseUp :, он работает только в том случае, если я привязываю myViewArray к NSArrayController.content в MyDocument. Произошел сбой организованного прокси-сервера. – erikprice

+0

«По какой-то причине я думал, что контроллер массива имеет некоторую способность слушать изменения в самом массиве». Это KVO. Контроллер массива добавляет себя в качестве наблюдателя для свойства bound-to; когда вы мутируете это свойство с помощью своих аксессуаров, KVO отправляет соответствующие уведомления, которые получает контроллер массива. –

+0

Хорошо, хорошо, потому что я так и думал. Спасибо, что поняли это. Тем временем я все еще пытаюсь понять, как NSArrayController можно использовать с массивом элементов NSValue, если мы должны быть привязаны к builtObjects (который, кажется, не раскрывает сами элементы непосредственно). – erikprice

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 
    

    Кроме этого, он смотрит на меня, как вы сделали все правильно связывании.

    обновление: Как об использовании 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 
      
      +0

      Да, я не включил его в фрагменты кода, но я выделяю и сохраняю NSMutableArray в методе init. Я не использовал переменную myViewArray MyView в свойстве - я попытаюсь это сделать, но, для завершения, это было мое предположение, что это также должно работать, если myViewArray - это просто переменная экземпляра экземпляра? – erikprice

      +0

      Я уверен, что myViewArray должен быть свойством. Система привязки какао в значительной степени зависит от системы уведомлений, а свойства @synthesized автоматически выполняют необходимые уведомления. –

      +0

      Ну, я добавил свойство, используя именно тот синтаксис, который вы рекомендуете, и, похоже, этого не было, на что я надеялся. Я полагаю, исходя из вашего кода, что не существует конфликта пространства имен между свойствами и переменными экземпляра? (ISTR, который по умолчанию использует переменную экземпляра с тем же именем, поэтому не должно быть.) – erikprice

      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

      Это не так. Вы должны привязать к организованным объектам. –

      +0

      Когда я изменяю привязку к builtObjects вместо содержимого (даже когда я реализую индексированные методы доступа, которые вы предлагаете в своем ответе), NSArrayController устанавливает myViewArray MyView для объекта, который не отвечает на метод insertObject: atIndex:, который я звоню из индексированного метода доступа: 2009-04-18 07: 20: 17.670 MYPROJ [37032: 10b] *** - [_ NSControllerArrayProxy insertObject: atIndex]: непризнанные селектор направлен например 0x16dea0 (сообщение об ошибке дважды печатается.) – erikprice

      +0

      Я продолжаю находить примеры кода в Интернете, которые поддерживают мою (возможно, неправильную) теорию о том, что «builtObjects» не предназначен для непосредственного привязки. Скорее, это полезный прокси-объект для ситуаций, когда вы хотите ссылаться на свойство элемента в массиве. Все примеры показывают привязки к «builtObject.someProperty», но никогда не просто «размещеныОбъекты». – erikprice

      1

      Прежде всего, нет ничего плохого с привязкой к arrangedObjects: NSTableColumn, например, должен иметь содержание связанное только arrangedObjects, и его contentValues ​​в arrangedObjects.someProperty.

      Общая ошибка заключается в том, чтобы рассматривать assemblyObjects как содержимое arrayController, но, как вы видели, приведет к горю: assemblyObjects - это представление о том, как arrayController в настоящее время упорядочивает объекты в своем контенте, а не сам контент.

      Тем не менее, способ связать массив с arrayController является:

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

      Вы уверены, что, кстати, ваш взгляд должен держать myViewArray? Обычно это подпадает под ответственность контроллера или модельного объекта.

      Теперь вы можете добавить объекты, вызвав addObject на arrayController, так как это ответственность диспетчера.

      [self.myArrayController addObject: anObject] 
      
      +0

      Для отображения этого вида необходимо удерживать массив. Но он не связывает содержимое контроллера массива с представлением, как вы показали; он привязывает его к документу. –

      +0

      К счастью, просмотр не должен содержать объект, чтобы отобразить его - это сделало бы шаблон MVC бесполезным, если бы они это сделали. Строго говоря, в представлении не отображается массив, он или, более вероятно, одно из его подзонов, отображает упорядоченные объекты объекта arrayController. Я не уверен, что вы подразумеваете под контентом arrayController, связанным с документом: как код Quinn Taylor, так и мои установленные привязки только между arrayController и массивом. –

      Смежные вопросы