Я создаю изменяемый массив, совместимый с KVC / KVO, на одном из моих объектов рекомендуемым способом:
@interface Factory {
NSMutableArray *widgets;
}
- (NSArray *)widgets;
- (void)insertObject:(id)obj inWidgetsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromWidgetsAtIndex:(NSUInteger)idx;
@end
Ясно, что это непростая проблема безопасности потоков. В методах insert и remove я блокирую доступ к массиву, чтобы предотвратить одновременное изменение, как рекомендуемые.
У меня вопрос: как правильно реализовать аксессуар widgets? Вот моя реализация:
- (NSArray *)widgets {
[widgetLock lock];
NSArray *a = [[widgets copy] autorelease];
[widgetLock unlock];
return a;
}
Это потокобезопасно?





Вам потребуется блокировка всех методов чтения и записи. Если ваши вставка и удаление также блокируются (как вы сказали), тогда метод доступа должен быть в порядке.
Ваш аксессор widgets должен быть в порядке, хотя вы должны знать, что ни один из объектов в этом массиве не заблокирован. Таким образом, вы можете столкнуться с проблемами, пытаясь одновременно запустить такой код, как
[[[myFactory widgets] objectAtIndex:7] setName:@"mildred"];
и
[myTextField setStringValue:[[[myFactory widgets] objectAtIndex:7] name]]; // mildred? or something else?
Поскольку объекты в вашем массиве не заблокированы, вы можете столкнуться с условиями гонки или проблемами типа читателей / писателей. Разве многопоточность не радует?
С другой стороны, для соответствия KVC я бы посоветовал реализовать objectInWidgetsAtIndex: и countOfWidgets вместо аксессуара widgets. Помните, что KVC моделирует отношения, а не свойства массива. Итак, вы должны вызвать что-то вроде [myFactory mutableArrayValueForKey:@"widgets"], чтобы получить массив, представляющий свойство widgets.
Вместо того, чтобы создавать свою собственную блокировку, вы также можете использовать блокировку, встроенную в язык:
т.е.
- (NSArray *)widgets {
@synchronized(widgets)
{
NSArray *a = [[widgets copy] autorelease];
return a;
}
}
и используйте аналогичную блокировку во всех других методах доступа к widgets. (Параметр widgets, переданный в @synchronized, относится к переменной экземпляра, а не к методу.)
Комментарий Алексея о доступе к содержащимся объектам все еще применяется.
@synchronized на самом деле устарел и медленнее, чем NSLock.