Ответ 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
.