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

В чем смысл кодирования с ключом?

Так как Objective-C 2.0, у нас были @properties и автогенерированные методы доступа. Итак, какова точка ключевого значения кодирования? При каких обстоятельствах предпочтительнее писать

[myObject setValue:foo forKey:@"bar"];

вместо записи

[myObject setBar:foo];

или даже

myObject.bar = foo;

Я продолжаю смотреть статьи и документацию с использованием KVC, но всегда так, как будто просто использовать свойства было бы лучше. Так почему я должен использовать KVC? Спасибо за любую информацию.

4b9b3361

Ответ 1

Почти никогда не рекомендуется записывать [myObject setValue:foo forKey:@"bar"] вручную, с буквальным @"bar". Обычно мы используем KVC для доступа к свойству, когда мы не знаем, какое свойство мы хотим получить до выполнения.

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

  • ссылка на текстовое поле (объект, имеющий выход)
  • ссылка на место владельца файла (место назначения соединения)
  • имя выхода в виде строки, @"delegate"

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

Еще один пример того, как не знать, какое свойство для доступа до выполнения является (малоизвестной) способностью Core Animation для анимации настраиваемого свойства вашего подкласса CALayer. Предположим, вы создали подкласс CALayer под названием PolygonLayer с свойством с именем sides. Вы можете анимировать свойство sides, используя стандартный CABasicAnimation:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"sides"];
animation.fromValue = @3;
animation.toValue = @9;
animation.autoreverses = YES;
animation.duration = 1;
[myPolygonLayer addAnimation:animation forKey:@"sides"];

Presto, Core Animation оживит ваш слой sides от 3 до 9 и обратно. Однако исходный код Core Animation ничего не знает о вашем свойстве sides. (Зайдите этот вопрос для более подробной информации.)

Иногда мы используем KVC, хотя мы знаем свойство во время компиляции. Одним из примеров является то, что мы хотим воспользоваться дополнительной работой, которую KVC сделает для нас. Например, если у вас есть NSArray полный объектов Person, и вы хотите получить массив каждого человека, вы можете написать это:

NSMutableArray *firstNames = [NSMutableArray array];
for (Person *person in people) {
    [firstNames addObject:person.firstName];
}

Но это случай, когда KVC имеет функцию, которая упрощает ее. Если вы получаете доступ к свойству массива с помощью KVC, KVC фактически получит доступ к этому свойству каждого элемента массива для вас:

NSArray *firstNames = [people valueForKey:@"firstName"];

Другой пример, где мы могли бы использовать KVC, даже если мы знаем, что свойство во время компиляции - это когда свойство не статически объявлено как часть класса. Например, каждый NSManagedObject (часть Core Data) динамически дает свойства на основе любой сущности, представляющей экземпляр NSManagedObject. Вы можете получить доступ к этим свойствам с помощью KVC, хотя обычно мы предпочитаем объявлять их в подклассе NSManagedObject или в категории NSManagedObject.

Ответ 2

KVC может быть полезна, если вы используете Key Value Observers для обнаружения изменений значения для объекта. Если вы хотите использовать KVO и @properties, вам придется обернуть каждый метод мутатора с помощью:

[self willChangeValueForKey:@"bar"];
bar = foo;
[self didChangeValueForKey:@"bar"];

Ответ 3

Иногда вы не знаете, какое свойство вы хотите установить/получить до запуска.
В этом случае вы можете использовать KVC, построив путь ключа свойства как строку.

Например, у меня есть объект с несколькими свойствами NSArray, и я хочу, чтобы последний NSDate был обновлен.

Скажем, у меня есть свойство массива, называемое: comments и свойство array, которое называется like.

Я определяю свойства: commentsLastModified и likesLastModified. когда массив обновляется (у меня есть имя свойства как строка), я использую:

[object setValue:[NSDate date] forKey:[NSString stringWithFormat:@"%@%@", arrayString, @"LastModified"];