Что такое кодирование значения ключа и наблюдение значения ключа в задаче C? - PullRequest
62 голосов
/ 26 ноября 2010

Может кто-нибудь объяснить простыми словами, что такое Key-Value-Coding и Key-Value-Observing?Пожалуйста, не предоставляйте ссылки на справочный документ Apple Developer.Я прошел через них.Я ожидаю объяснения в очень простых терминах.

Ответы [ 4 ]

118 голосов
/ 26 ноября 2010

Key-Value-Coding (KVC) означает доступ к свойству или значению с использованием строки.

id someValue = [myObject valueForKeyPath:@"foo.bar.baz"];

Что может совпадать с:

id someValue = [[[myObject foo] bar] baz];

Key-Value-Наблюдение (KVO) позволяет вам наблюдать за изменениями в свойстве или стоимости.

Для наблюдения свойства с помощью KVO вы бы идентифицировали свойство с помощью строки;то есть используя KVC.Следовательно, наблюдаемый объект должен соответствовать KVC.

[myObject addObserver:self forKeyPath:@"foo.bar.baz" options:0 context:NULL];
28 голосов
/ 26 ноября 2010

Код ключевого значения - это простой доступ к свойству объекта через строку вместо буквального синтаксиса.

// Here is a new instance of an object
Foo *foo = [[Foo alloc] init];
// Accessing a property called someValue with literal syntax:
[foo someValue];
// Accessing the same property with dot notation
foo.someValue;
// Accessing the same property with Key-Value coding:
[foo valueForKey:@"someValue"];

Сила KVC в том, что вы можете указать любую произвольную строку во время выполнения (очевидно, это тоже может быть очень опасно).

12 голосов
/ 10 апреля 2014

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

NSNumber* foo = [myPopup valueForKey: @"selectedItemIndex"];
[myPopup setValue: @15 forKey: @"selectedItemIndex"];

Хорошим примером для этого является NSTableView на Mac, где вы можете просто установить идентификатор для каждого столбца таблицы, который соответствует свойству объекта модели, который он должен отображать, а затем ваш источник данных просто вызывает -valueForKey: / - setValue: forKey: с идентификатором столбца в качестве ключа и значения в значительной степени отображаются / устанавливаются сами. Вы просто добавляете правильные столбцы в табличное представление в XIB.

Наблюдение за значением ключа было добавлено позже и позволяет вам регистрироваться, чтобы получать уведомления об изменениях, внесенных в другой объект. Вы регистрируете свой интерес, выполнив:

void*    gMyKVOContext = &gMyKVOContext; // global variable somewhere that guarantees us a unique address that doesn't collide with a subclass's registration for observing the same property

...

[interestingObject addObserver: interestedObject forKeyPath: @"interestingProperty" options: 0 context: gMyKVOContext];

Всякий раз, когда это свойство изменяется, -observeValueForKeyPath: ofObject: change: context: будет вызываться для объекта, который вы указали в качестве наблюдателя. Таким образом, вы бы реализовали это как:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if( context == gMyKVOContext && [keyPath isEqualToString: @"interestingProperty"] )
    {
        // Update UI that shows interestingProperty
    }
    else
        [super observeValueForKeyPath: keyPath ofObject: object change: change context: context];
}

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

Чтобы сделать свойство наблюдаемым, либо используйте реализацию @synthesized по умолчанию, когда вы определяете его, либо, если вы определяете его самостоятельно, реализуйте установщик следующим образом:

-(void)  setFoo: (int)inFoo
{
    [self willChangeValueForKey: @"foo"];
    _foo = inFoo;
    [self didChangeValueForKey: @"foo"];
}

Тогда всегда проходите через установщик, чтобы изменить его, не меняйте _foo напрямую. Если у вас есть связанные свойства, которые могут противоречить друг другу, как указано выше, хороший способ избежать этого - всегда менять их оба парами (однако, тогда вы не можете использовать KVC). Для этого реализуем комбинированный сеттер, например:

-(void) setFoo: (int)inFoo bar: (int)inBar
{
    [self willChangeValueForKey: @"foo"];
    [self willChangeValueForKey: @"bar"];
    _foo = inFoo;
    _bar = inBar;
    [self didChangeValueForKey: @"bar"];
    [self didChangeValueForKey: @"foo"];
}

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

7 голосов
/ 26 ноября 2010

Начните здесь.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...