2009-07-23 3 views
36

У меня была трещина при реализации привязок для моего собственного подкласса NSView. Он работает, но есть проблемы с циклами сохранения при привязке к File's Owner из файла nib. Немного поучившись, я обнаружил, что Apple имела такую ​​же проблему несколько лет назад, но исправила ее каким-то магическим недокументированным классом (NSAutounbinder).Можете ли вы вручную реализовать привязки какао?

Здесь подробно обсуждается проблема цикла удержания http://www.cocoabuilder.com/archive/message/cocoa/2004/6/12/109600. Обходной путь заключается в том, чтобы развязать все привязки, прежде чем оконный контроллер будет освобожден, не раньше освобожден, в месте, таком как windowWillClose :. Мне это кажется ненужным.

Мой вопрос заключается в следующем: есть ли способ сделать пользовательские привязки, которые работают так же хорошо, как те, которые сделаны Apple, без использования недокументированных функций? Неужели я ошибаюсь?


ОБНОВЛЕНИЕ 2: Я нашел решение, которое позволяет вручную внедренные привязки работать точно так же, как привязки Apple. Он использует недокументированный класс NSAutounbinder, фактически не используя недокументированные функции. Я отправлю решение позже сегодня.


UPDATE: Я попытался с помощью exposeBinding:, и это, кажется, не имеет никакого значения. Однако реализация NSObjectbind:toObject:withKeyPath:options: работает наполовину. Он пропагандирует изменения от bindee до связующего (то есть от модели/контроллера для просмотра), но не работает обратным образом. Кроме того, хотя наблюдатель, очевидно, наблюдается, observeValueForKeyPath:ofObject:change:context: никогда не срабатывает.

Пример проекта здесь: http://www.tomdalling.com/wp-content/BindingsTest.zip

документация Apple, указывает на то, что вы, по сути, должны переопределить bind:toObject:withKeyPath:options: для осуществления ручного привязок. Смотрите здесь: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html


SIDE ПРИМЕЧАНИЕ: Я исследовал, как работает без документов NSAutounbinder, и вот что я знаю.

Когда привязка создается в NSWindowController, связанный объект на самом деле является NSAutounbinder, который получен из NSWindowController с - [NSWindowController _autounbinder]. NSAutounbinder - не сохраняющий прокси-сервер для объекта NSWindowController. Он не удерживает, чтобы избежать проблемы с циклом сохранения.

Когда - вызывается [NSWindowController release] и сохраняетсяCount == 1, NSAutounbinder отсоединяет все привязки к себе. Это гарантирует, что к объекту не будут висящие указатели до его освобождения.

+0

Пока CocoaBuilder не работает, вы можете найти соответствующую тему на http://lists.apple.com/archives/cocoa-dev/2004//Jun/msg00835.html – s4y

ответ

21

Вот лучшее решение, которое я могу найти. У меня есть более подробное обсуждение и демо-код здесь: http://tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/

В принципе, вы НЕ переопределение bind:toObject:withKeyPath:options: или unbind:. Реализация по умолчанию на NSObject будет использовать NSAutounbinder, чтобы избежать циклов удержания. Как отметил Луи Гербарг, все еще есть ситуации, когда NSAutounbinder не влезает. Однако вы можете добиться того, чтобы ваши привязки работали как минимум так же, как привязки Apple.

Поскольку реализация по умолчанию bind:toObject:withKeyPath:options: не обновляет модель при изменении вида, изменения, связанные с изменением вида, должны передаваться вручную. Вы можете использовать -[NSObject infoForBinding:], чтобы получить всю информацию, необходимую для обновления связанного объекта. Я добавил свой собственный метод на NSObject с категорией:

-(void)propagateValue:(id)value forBinding:(NSString*)binding; 

Он обрабатывает получение связанного объекта, связанный ключевой путь, и применяя трансформатор значения. Реализация доступна по ссылке вверху.

+0

Я недавно написал ответ на соответствующий вопрос, прежде чем найти этот пост. Я исправлю, что использование 'exposeBinding:' работает в тех случаях, когда представление не нуждается в распространении изменений в модели? http://stackoverflow.com/questions/366938/is-it-necessary-to-override-bindtoobjectwithkeypathoptions-in-an-nsview-subcl/7394273#7394273 – paulmelnikow

+0

'exposeBinding:' фактически ничего не делает за пределами Interface Builder если я правильно помню. Все, что он делает, - это сделать вашу привязку отображаемой в GUI интерфейса интерфейса. –

2

Возможно, вы захотите проверить NSKeyValueBindingCreation Protocol. Он позволяет создавать привязки программным путем через код. (Не забудьте выполнить работу в awakeFromNib-методе, если вам нужно ссылаться на переменные IBOutlet, или они могут быть ноль.)

+2

Спасибо за ваш ответ, но я пытаюсь реализовать собственные привязки для пользовательского класса, а не использовать существующие привязки. –

+0

Я думаю, что это метод + exposeBinding: для этого протокола. Конечно, я мог ошибаться, но это, похоже, документированный и санкционированный способ создания ваших собственных привязок. –

+0

protectedBindings используется только для создания плагинов построителя интерфейса из того, что я читал –

3

Короткий ответ: нет, вы не можете заставить его работать без обходного пути в вызывающем коде и крупка. Даже NSAutounbinder пропускает некоторые случаи для NSDocument и NSWindowController, если Apple не может заставить его работать правильно для 2 классов, которые они специально обучают тех из нас, у которых нет доступа к интранатам AppKit, в принципе нет шансов.

Сказав это, есть два обходных пути, которые, возможно, немного приятнее, чем развязка в windowWillClose :.

  1. Не связываться с файла владельца, но вместо того, чтобы перетащить NSObjectController как объект корневого уровня в бобах и привязать к этому, то setContents: на контроллере объекта во время awakeFromNib.
  2. Включите сбор мусора. Если это вариант, он решает все проблемы с циклом объектов ;-) Очевидно, что GC вводит свои собственные проблемы, и если вам нужна совместимость 10.4, это не стартер.
2

См. Пример mmalc's GraphicsBindings для примера того, как реализовать свои собственные привязки. Вам необходимо реализовать неофициальный протокол NSKeyValueBindingCreation, чтобы заставить его работать. Для того, чтобы ваши контроллеры знают, что есть вещи, которые могут быть связаны, вызовите exposeBinding в + (ID) инициализировать метод вашего зрения:

+ (void)initialize { [self exposeBinding:@"ILIKEBINDAGE"]; } 

Затем вам нужно реализовать каждый из привязок управляющих методами в NSKeyValueBindingCreation протокол. Вам в основном нужно настроить KVO для представления, чтобы он знал, когда нужно обновлять на основе поведения приложения и обрабатывать очистку (unbind :).

Это много лишнего, довольно уродливого кода, поэтому может быть, что использование традиционного кода клея работает лучше и его легче читать.

+1

Пример mmalc GraphicsBindings содержит проблему цикла сохранения, о которой я упоминал. Кроме того, exposeBinding: обсуждался в ответе Райана Баллантайн. –

+2

К сожалению, это мертвая ссылка. – uchuugaka

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