Должны ли отношения «ко-многим» моделироваться как свойства? - PullRequest
7 голосов
/ 03 июня 2009

После прочтения Руководства по программированию кодирования значения ключа , Руководства по программированию наблюдения значения ключа и Руководства по реализации объекта модели , а также прочтения многих StackOverflow записи по теме и экспериментируя с различными сценариями моделирования, я чувствую, что у меня есть хорошее представление о том, как моделировать мои данные.

В итоге я использую объявленные свойства для всех своих атрибутов и отношений «один к одному», подкрепленных приватными ivars. Для атрибутов только для чтения, которые должны быть доступны для частной записи, я использую атрибут readonly в объявлении интерфейса .h, затем повторно объявляю свойство с атрибутом readwrite в расширении класса, объявленном в файле .m , Внутри методов класса я всегда использую методы доступа к свойствам с точечным синтаксисом и никогда не получаю прямой доступ к закрытым иварам.

Однако есть один аспект, который все еще оставляет меня озадаченным: как правильно моделировать отношения ко многим, особенно когда коллекция должна быть публично неизменной, но частно изменяемой (то есть потребители объекта модели не могут добавлять или удалять объекты в коллекция, но содержание коллекции управляется классом в частном порядке).

Я понимаю, как реализовать методы доступа KVC для отношений ко многим (countOf<Key>, objectsIn<Key>AtIndex и т. Д.), И по этому пути я следовал до сих пор.

Однако я видел некоторый пример кода, который использует объявленные свойства для раскрытия отношений, не реализует методы доступа KVC, но все еще является наблюдаемым Key-Value. Например:

@interface MyModel : NSObject
{
  // Note that the ivar is a mutable array,
  // while the property is declared as an immutable array.
  @private NSMutableArray *transactions_;
}

@property (nonatomic, retain, readonly) NSArray transactions;

@end

--------------------

@implementation MyModel

@synthesize transactions = transactions_;

- (void)privateMethodThatManagesTransactions
{
  [[self mutableArrayValueForKey:@"transactions"] addObject:t];
}

@end

Если объект-потребитель добавляет себя в качестве наблюдателя экземпляра MyModel для ключевого пути "transactions", он будет уведомляться о добавлении или удалении транзакций из коллекции transactions (до тех пор, пока выполняются мутации). с помощью метода mutableArrayValueForKey:).

Мне кажется, это самый чистый способ раскрыть отношения ко многим, поскольку мне не нужно вручную кодировать средства доступа к коллекции KVC, и он сохраняет код в чистоте.

Тем не менее, похоже, что это не продвигается в документации Apple, и я не могу не задаться вопросом, является ли факт, что это работает, ненадежным побочным эффектом.

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

Таким образом, вопрос заключается в следующем: если я использую свойства для моделирования отношений ко многим, мне все еще нужно реализовать методы доступа / мутатора KVC?

Обновление

Даже когда я объявляю свойство to-many как readonly, как в примере выше, внешний код все равно может вызывать mutableArrayValueForKey:@"transactions" для объекта модели и изменять коллекцию. Похоже, это указывает на то, что использование объявленных свойств для отношений ко-многим - это не тот путь, но я все еще чувствую, что не совсем понимаю ...

1 Ответ

6 голосов
/ 03 июня 2009

Да.

Однако есть один аспект, который все еще оставляет меня озадаченным: как правильно моделировать отношения ко многим, особенно когда коллекция должна быть публично неизменной, но частно изменяемой….

Easy: объявите свойство как readonly в заголовке, затем повторно объявите его как readwrite, copy в расширении класса в файле реализации.

Я понимаю, как реализовать методы доступа KVC для отношений ко многим (countOf<Key>, objectsIn<Key>AtIndex и т. Д.), И по этому пути я следовал до сих пор.

Есть и мутативные. С ними вам не нужно использовать mutableArrayValueForKey:; вместо этого вы можете использовать мутативные аксессоры напрямую. Вы по-прежнему будете получать уведомления KVO, потому что KVO оборачивает эти методы в первый раз, когда что-то добавляет себя в качестве наблюдателя для свойства.

У меня есть список форматов селекторов доступа , включая мутативные аксессоры, в моем блоге.

Edit:

Даже когда я объявляю свойство to-many только для чтения, как в примере выше, внешний код все равно может вызывать mutableArrayValueForKey:@"transactions" для объекта модели и изменять коллекцию.

Это хорошая причина для того, чтобы использовать привычные средства доступа и избегать mutableArrayValueForKey:. Вы не будете отправлять сообщения о мутациях из-за пределов класса, если вы будете получать предупреждение компилятора (такого метода нет [public]) каждый раз, когда вы его пробуете.

Несмотря на наличие mutableArrayValueForKey: и риск того, что кто-то его использует, KVO-совместимые свойства являются подходом.

...