Массив KVC: геттеры против индексированных аксессоров?

Меня это смущает: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/AccessorConventions.html#//apple_ref/doc/uid/20002174-178830-BAJEDEFB

Предположим

@interface Office : NSObject {
  NSMutableArray *employees;
}
  1. В чем преимущество реализации методов доступа к коллекциям?

  2. Чем [anOffice countOfEmployees] лучше, чем [[anOffice employees] count]?

  3. Зависят ли привязки от аксессуаров коллекции или я могу полностью отказаться от них? Мне они кажутся излишними, поскольку я использую настоящий объект массива. Я понимаю, как они понадобились бы, если бы сотрудники не были NSMutableArray и не реализовали что-то вроде самого метода подсчета.

  4. Я также совершенно озадачен тем, зачем использовать mutableArrayValueForKey:@"employees" для получения свойства сотрудников вместо простого valueForKey:@"employees".

Спасибо!


person Alexandre    schedule 23.08.2010    source источник


Ответы (1)


Вы можете отказаться от средств доступа к коллекции; они не требуются. Но они значительно упрощают жизнь.

Одна из причин их использования, включая countOfEmployees, - эффективность: метод employees может возвращать копию объекта массива (особенно потому, что копия Office является изменяемой, поэтому Office не захочет, чтобы другие объекты изменяли массив из-под него), но если вам нужно знать только счетчик или получить доступ к одному объекту по определенному индексу, вам не нужна копия.

Другая причина заключается в том, что отправитель хочет изменить свойство.

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

mutableArrayValueForKey: возвращает поддельный массив, который отправляет сообщения о мутации (или, если ничего другого, сообщения employees и setEmployees:) обратно исходному объекту. Сообщения аксессуаров действительно вызывают уведомления KVO, поэтому все, что наблюдает за свойством, будет следовать вместе с этими изменениями, поэтому ваш пользовательский интерфейс будет актуальным.

Конечно, вы можете просто отправить сообщения аксессора самостоятельно. mutableArrayValueForKey: в основном используется, если вы хотите внести изменения в свойство, которое неизвестно во время компиляции; NSArrayController, по-видимому, является одним из пользователей этого метода. Скорее всего, вам не понадобится использовать mutableArrayValueForKey: в обычном приложении, а саму отправку сообщений доступа, на мой взгляд, легче читать.

Все это относится и к Office, когда он изменяет свой собственный массив. Он мог просто разговаривать со своим объектом массива напрямую, но это не приводило бы к уведомлениям KVO, поэтому ничто другое не узнало бы об изменении значения свойства. Вы можете сами публиковать уведомления KVO при каждом изменении, но это хлопотно, и их легко забыть. Средства доступа к коллекциям и mutableArrayValueForKey: - два решения этих проблем: Каждый доступ представляет собой одну строку кода, которая вызывает уведомления KVO.

person Peter Hosey    schedule 23.08.2010
comment
Почему [[сотрудники anOffice] insertObject: ...] не KVC? Предположительно, объекты, наблюдающие за массивом сотрудников, должны получать уведомление при его вызове. Во-вторых, почему вы рекомендуете получателю сотрудников вернуть неизменяемую копию? Спасибо, Питер. - person Alexandre; 23.08.2010
comment
@Alexandre: Я не знаю, почему вы так думаете. Это не так. Мутация массива не создает никаких уведомлений KVO - массив не знает, кто за ним наблюдает, и ему все равно. Уведомления об изменениях выдаются контроллером, ответственным за массив, и их не произойдет, если вы зайдете за спину контроллера и напрямую измените массив. - person Chuck; 23.08.2010
comment
Получатель не должен возвращать исходный массив, потому что тогда вызывающий может изменить массив за спиной контроллера, что вызовет проблемы. Если вы вернете изменяемую копию, вызывающий может изменить этот массив, поэтому [[anOffice employees] insertObject:…] не выйдет из строя, но он также не изменит сотрудников офиса, потому что он мутирует копию. Код, который не делает того, что кажется, плох. Возврат неизменяемой копии гарантирует, что вызывающий объект не может изменить исходный массив или ошибочно поверить в то, что он это делает. - person Peter Hosey; 23.08.2010
comment
@Chuck: Вы предполагаете, что объект Office является контроллером массива? Я должен был уточнить, что NSArrayController привязан к свойству сотрудников Office. В этом случае за кем наблюдает NSArrayController: за объектом Office или за массивом сотрудников? Похоже, он должен непосредственно наблюдать за массивом сотрудников, чтобы он мог перехватывать такие методы, как addObject и т. Д. @Peter: Извините, что повторяю себя - вы предполагаете, что объект Office является контроллером массива? Я должен был уточнить, что NSArrayController привязан к свойству сотрудников Office. - person Alexandre; 24.08.2010
comment
Александр: Да, был. Хотя это не имеет значения; независимо от того, является ли Office моделью или контроллером, контроллер массива (NSArrayController) наблюдает за этим свойством Office. Он не наблюдает за массивом напрямую - это невозможно, поскольку KVO-уведомления всегда описываются в терминах свойства некоторого объекта. См. Протокол KVO, особенно его сторону наблюдателя: developer.apple.com/mac/library/documentation/Cocoa/Reference/ - person Peter Hosey; 24.08.2010