Ответ 1
Вы не можете читать и писать свойства на нескольких потоках без применения какой-либо безопасности потоков. Теперь, в принципе, для простого объекта, такого как строка, может быть достаточно просто применить atomic
. См. В чем разница между атомными и неатомическими атрибутами? Подробнее о том, что это делает.
Честно говоря, мне очень не нравится atomic
. Я знаю, что он делает, но это кажется громоздким способом добраться до того, что вы действительно хотите (и часто заканчивается меньше, чем вы хотите). И это не очень общее решение; Я не могу настроить аксессуар atomic
"немного" (например, добавить setNeedsDisplay
или тому подобное).
Вот почему мне нравятся аксессоры на основе очереди. Они немного больше работают, но они эффективны для множества проблем.
@property (nonatomic, readwrite, strong) dispatch_queue_t thingQueue;
@property (nonatomic, strong) NSObject *thing;
- (id)init {
...
_thingQueue = dispatch_queue_create("...", DISPATCH_QUEUE_CONCURRENT);
...
}
- (NSObject *)thing {
__block NSObject *thing;
dispatch_sync(self.thingQueue, ^{
thing = _thing;
});
return thing;
}
- (void)setThing:(NSObject *)thing {
dispatch_barrier_async(self.thingQueue, ^{
_thing = thing;
});
}
Что мне нравится в этой системе, так это то, что она позволяет всем читателям, как вы хотите, параллельно. Когда писатель пытается сделать обновление, гарантированно не голодать, независимо от того, сколько читателей задействовано. И он всегда возвращается быстро. Также есть явная точка в очереди, когда значение изменяется, так что читатели, которые запрашивали значение до писателя, всегда получат старое значение, а читатели после писателя всегда получат новое значение, независимо от того, сколько раз в очереди.
Ключ состоит в том, что геттер является синхронным, поэтому он будет ждать, пока он не сможет получить значение, а сеттер включает в себя барьер. Барьер означает, что "никакие другие блоки не могут быть запланированы из этой очереди во время работы". Таким образом, у вас есть куча блоков считывателя, работающих параллельно, тогда барьер сеттера приходит и ждет, пока все читатели закончат. Затем он запускается один, устанавливая значение, а затем читатели за ним могут снова работать параллельно.