Регистрация зависимых ключей

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

К - отношения

Для инициирования уведомлений автоматически для к - одно отношение, необходимо или переопределить keyPathsForValuesAffectingValueForKey: или реализуйте подходящий метод, следующий за образцом, который он определяет для регистрации зависимых ключей.

Например, полное имя лица зависит от обоих имя и фамилия. Метод, возвращающий полное имя, мог быть записан следующим образом:

- (NSString *)fullName {
    return [NSString stringWithFormat:@"%@ %@",firstName, lastName];
}

Приложение, наблюдая fullName свойство должно быть уведомлено когда любой firstName или lastName изменение свойств, поскольку они влияют на значение свойства.

Одно решение состоит в том, чтобы переопределить keyPathsForValuesAffectingValueForKey: указание, что fullName свойство лица зависит от lastName и firstName свойства. Перечисление 1 показывает реализацию в качестве примера такой зависимости:

  Реализация перечисления 1 В качестве примера keyPathsForValuesAffectingValueForKey:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
 
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
 
    if ([key isEqualToString:@"fullName"]) {
        NSArray *affectingKeys = @[@"lastName", @"firstName"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

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

Можно также достигнуть того же результата путем реализации метода класса, следующего соглашению о присвоении имен keyPathsForValuesAffecting<Key>, где <Key> имя атрибута (первая капитализируемая буква), который зависит от значений. Используя этот образец код в Перечислении 1 мог быть переписан как названный метод класса keyPathsForValuesAffectingFullName как показано в Перечислении 2.

  Реализация перечисления 2 В качестве примера keyPathsForValuesAffecting<Key> соглашение о присвоении имен

+ (NSSet *)keyPathsForValuesAffectingFullName {
    return [NSSet setWithObjects:@"lastName", @"firstName", nil];
}

Вы не можете переопределить keyPathsForValuesAffectingValueForKey: метод, когда Вы добавляете вычисленное свойство к существующему классу с помощью категории, потому что Вы не предполагаетесь к переопределенным методам в категориях. В этом случае реализуйте соответствие keyPathsForValuesAffecting<Key> метод класса использовать в своих интересах этот механизм.

К - много отношений

keyPathsForValuesAffectingValueForKey: метод не поддерживает ключевые пути, включающие в - многие отношение. Например, предположите, что Вы сделали, чтобы Отдел возразил с против - многие отношение (employees) Сотруднику и Сотруднику имеет атрибут зарплаты. Вы могли бы хотеть объект Отдела, имеют a totalSalary атрибут, зависящий от зарплат всех Сотрудников в отношении. Вы не можете сделать этого с, например, keyPathsForValuesAffectingTotalSalary и возврат employees.salary как ключ.

В обеих ситуациях существует два возможных решения:

  1. Можно использовать наблюдение значения ключа для регистрации родителя (в этом примере, Отделе) как наблюдатель соответствующего атрибута всех дочерних элементов (Сотрудники в этом примере). Необходимо добавить и удалить родителя как наблюдатель, поскольку дочерние объекты добавлены к и удалены из отношения (см. Регистрацию для Наблюдения Значения ключа). В observeValueForKeyPath:ofObject:change:context: метод Вы обновляете зависимое значение в ответ на изменения, как проиллюстрировано в следующем фрагменте кода:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
     
        if (context == totalSalaryContext) {
            [self updateTotalSalary];
        }
        else
        // deal with other observations and/or invoke super...
    }
     
    - (void)updateTotalSalary {
        [self setTotalSalary:[self valueForKeyPath:@"employees.@sum.salary"]];
    }
     
    - (void)setTotalSalary:(NSNumber *)newTotalSalary {
     
        if (totalSalary != newTotalSalary) {
            [self willChangeValueForKey:@"totalSalary"];
            _totalSalary = newTotalSalary;
            [self didChangeValueForKey:@"totalSalary"];
        }
    }
     
    - (NSNumber *)totalSalary {
        return _totalSalary;
    }
  2. При использовании Базовых Данных можно зарегистрировать родителя в центре уведомления приложения как наблюдатель его контекста управляемого объекта. Родитель должен реагировать на соответствующие уведомления изменения, отправленные дочерними элементами способом, подобным этому для наблюдения значения ключа.