Подтвердить что ты не робот

Можете ли вы вручную реализовать привязки Cocoa?

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

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

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


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


UPDATE: Я пробовал использовать exposeBinding:, и, похоже, это не имеет значения. Однако реализация NSObject работы bind: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


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

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

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

4b9b3361

Ответ 1

Вот лучшее решение, которое я могу найти. У меня есть более подробное обсуждение и демо-код здесь: 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;

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

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

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

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