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

Что такое кодирование ключевых значений и наблюдение за ключевыми значениями в Objective C?

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

4b9b3361

Ответ 1

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

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

Что может быть таким же:

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

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

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

[myObject addObserver:self forKeyPath:@"foo.bar.baz" options:0 context:NULL];

Ответ 2

Key Value Coding - это просто доступ к объекту объекта через строку вместо синтаксиса literal.

// 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 заключается в том, что вы можете указать любую произвольную строку во время выполнения (очевидно, это тоже может быть очень опасно).

Ответ 3

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

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 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"];
}

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

Ответ 4

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

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