Наблюдение NSUserDefaultsController не работает, когда установлены связанные свойства - PullRequest
2 голосов
/ 25 января 2010

Вот настройка: у меня есть подкласс IKImageBrowserView, чье свойство zoomValue связано с ключом VFBrowserZoomValue в общем NSUserDefaultsController. У меня есть NSSlider, привязка value которого связана с тем же ключом.

Это прекрасно работает для изменения zoomValue браузера с ползунка.

Я пытаюсь внедрить -magnifyWithEvent: в моем подклассе IKImageBrowserView, чтобы разрешить масштабирование браузера жестом-пинчем на трекпадах.

Вот моя реализация:

-(void)magnifyWithEvent:(NSEvent *)event
{
  if ([event magnification] > 0) {
    if ([self zoomValue] < 1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
  } 
  else if ([event magnification] < 0) {
    if ([self zoomValue] + [event magnification] > 0.1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
    else {
      [self setZoomValue: 0.1];
    }
  }
}

Это правильно изменяет браузер zoomValue. Проблема в том, что NSUserDefaults не обновляется с новым значением.

В другом месте приложения у меня есть реализация -observeValueForKeyPath:ofObject:change:context:, которая соответствует браузеру zoomValue. Если я регистрирую значения масштабирования браузера, значения ползунка и значения по умолчанию для этого метода, я вижу, что zoomValue браузера не было помещено в NSUserDefaults, и ползунок не обновился.

Я пытался окружить метод -magnifyWithEvent: вызовами -{will,did}ChangeValueForKey безрезультатно.

Ответы [ 3 ]

4 голосов
/ 26 января 2010

Поток КВО для привязок не является ортогональным; привязка - это не свойство , это ссылка на свойство. Это краткое описание того, как работают привязки:

  • KVO используется для передачи изменений от модели к контроллеру и представлению.
  • KVC используется для передачи изменений от вида к контроллеру и модели.

Таким образом, когда представление с привязками обрабатывает события, оно должно распространять изменения свойств, на которые ссылаются его привязки.

Вот как может выглядеть ваш код с помощью вспомогательного метода для тяжелой работы по распространению изменений через привязки:

- (void)magnifyWithEvent:(NSEvent *)event
{
  if ([event magnification] > 0) {
    if ([self zoomValue] < 1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
  } 
  else if ([event magnification] < 0) {
    if ([self zoomValue] + [event magnification] > 0.1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
    else {
      [self setZoomValue: 0.1];
    }
  }

  // Update whatever is bound to our zoom value.
  [self updateValue:[NSNumber numberWithFloat:[self zoomValue]]
         forBinding:@"zoomValue"];
}

Немного прискорбно, что ImageKit требует использования @"zoomValue" для ссылки на привязку Zoom Value IKImageBrowserView, большинство привязок в AppKit имеют собственную глобальную строковую константу, например NSContentBinding.

И вот этот универсальный служебный метод для распространения изменений через привязку:

- (void)updateValue:(id)value forBinding:(NSString *)binding
{
  NSDictionary *bindingInfo = [self infoForBinding:binding];

  if (bindingInfo) {
    NSObject *object = [bindingInfo objectForKey:NSObservedObjectKey];
    NSString *keyPath = [bindingInfo objectForKey:NSObservedKeyPathKey];
    NSDictionary *options = [bindingInfo objectForKey:NSOptionsKey];

    // Use options to apply value transformer, placeholder, etc. to value
    id transformedValue = value; // exercise for the reader

    // Tell the model or controller object the new value
    [object setValue:transformedValue forKeyPath:keyPath];
  }
}

Фактическое применение заполнителей, преобразователей значений и т. П. Оставлено в качестве упражнения для читателя.

0 голосов
/ 25 января 2010

Когда вы создаете элемент управления, совместимый с привязками (или, в вашем случае, подклассы один), это элемент управления, чтобы уведомить контроллер при изменении его значения. Итак, что вы хотите сделать, это переопределить

- (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options

и следите за интересующей вас связью. Следите за observableController и keyPath (а также за словарем options, если будут использоваться любые преобразователи значения). Когда вы обновите значение вашего элемента управления, вам нужно будет отправить

[observableController setValue:newValue forKeyPath:keyPath];

для обновления контроллера новым значением. Наблюдение за ключевыми значениями - это улица с односторонним движением, а в привязках контроль - это наблюдатели.

0 голосов
/ 25 января 2010

Боюсь, что это ожидаемое поведение, см. этот раздел часто задаваемых вопросов документации по привязке. Вы должны нажать это вручную.

...