Избегайте этого свисающего указателя с ARC
У меня есть объект, который содержит strong
ссылка на объект:
@property (nonatomic, strong) NSObject *thing;
В другом месте у меня есть метод, который передает ссылку на объект:
[thirdObject doSomething:secondObject.thing];
В одном случае (из миллиона или миллиарда) третий объект в итоге работал с висящим указателем, потому что объект был заменен и не имел владельца.
Могу ли я избежать этого, сделав это? Это отличается от ARC?
NSObject *thing = secondObject.thing
[thirdObject doSomething:secondObject.thing];
Если нет, как я могу избежать этого?
Редактировать: Сообщение является "сообщением, отправленным на освобожденный экземпляр 0xwhither"
1 ответ
Вы не можете читать и записывать свойства в нескольких потоках, не применяя какой-либо потокобезопасности. Теперь, в принципе, для простого объекта, такого как строка, может быть, просто применяя atomic
было бы достаточно. См. В чем разница между атомарными и неатомарными атрибутами? больше о том, что именно это делает.
Честно говоря мне очень не нравится atomic
очень сильно. Я знаю, что он делает, но это кажется обременительным способом получить то, что вы действительно хотите (и часто оказывается меньше, чем вы хотите). И это не очень общее решение; Я не могу настроить atomic
Accessor "немного" (хотел бы добавить 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;
});
}
Что мне нравится в этой системе, так это то, что она позволяет всем читателям работать так, как вы хотите, параллельно. Когда автор пытается сделать обновление, он гарантированно не голодает, независимо от того, сколько читателей вовлечено. И всегда возвращается быстро. Существует также четкая точка в очереди, когда значение изменяется, так что читатели, которые запрашивали значение до записи, всегда получат старое значение, а читатели после записи всегда получат новое значение, независимо от того, насколько велика конкуренция. в очереди.
Ключевым моментом является то, что метод получения является синхронным, поэтому он будет ждать, пока не получит значение, и метод установки включает в себя барьер. Барьер означает "никакие другие блоки не могут быть запланированы из этой очереди, пока я работаю". Таким образом, у вас есть несколько блоков считывателей, работающих параллельно, затем появляется установочный барьер и ожидает завершения всех считывателей. Затем он запускается в одиночку, устанавливая значение, а затем читатели, стоящие за ним, могут снова работать параллельно.