Когда я использую objc_setAssociatedObject
, я знаю, следует ли использовать сохранение или назначение, но я не знаю, как выбирать между OBJC_ASSOCIATION_RETAIN
и OBJC_ASSOCIATION_RETAIN_NONATOMIC
. Когда следует использовать одно или другое?objc_setAssociatedObject сохранить атомный или неатомный
ответ
Если значение, которое вы пытаетесь сохранить, будет использовать атрибут nonatomic
, если это свойство, используйте OBJC_ASSOCIATION_RETAIN_NONATOMIC
, в противном случае используйте OBJC_ASSOCIATION_RETAIN
.
Существует мало причин использовать атомарность (OBJC_ASSOCIATION_RETAIN
). В большинстве случаев безопасность потоков не может быть достигнута путем обеспечения безопасности потока данных. Это больший предмет.
Для свойств есть побочный эффект атомизма, который считывает значение autoreleased. Но ни один из них не документирован для связанных объектов, и это не полезно в ARC раз.
Так что мой совет: используйте OBJC_ASSOCIATION_RETAIN_NONATOMIC
.
Резюме: Вы должны использовать OBJC_ASSOCIATION_RETAIN
, если вы могли бы назвать objc_setAssociatedObject
на одну нить, и objc_getAssociatedObject
в другом потоке, одновременно, с теми же object
и key
аргументов.
окровавленные детали:
Вы можете посмотреть на реализацию objc_setAssociatedObject
в objc-references.mm
. Но на самом деле разница между OBJC_ASSOCIATION_RETAIN
и OBJC_ASSOCIATION_RETAIN_NONATOMIC
имеет значение только для objc_getAssociatedObject
.
Вот определения этих констант в <objc/runtime.h>
:
enum {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
Обратите внимание, что 01401
является 0x0301
и 01403
является 0x0303
. Исходный код разбивает их дальше вниз:
enum {
OBJC_ASSOCIATION_SETTER_ASSIGN = 0,
OBJC_ASSOCIATION_SETTER_RETAIN = 1,
OBJC_ASSOCIATION_SETTER_COPY = 3, // NOTE: both bits are set, so we can simply test 1 bit in releaseValue below.
OBJC_ASSOCIATION_GETTER_READ = (0 << 8),
OBJC_ASSOCIATION_GETTER_RETAIN = (1 << 8),
OBJC_ASSOCIATION_GETTER_AUTORELEASE = (2 << 8)
};
Таким образом, мы можем видеть, что OBJC_ASSOCIATION_RETAIN_NONATOMIC
просто OBJC_ASSOCIATION_SETTER_RETAIN
, но на самом деле OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_SETTER_RETAIN | OBJC_ASSOCIATION_GETTER_RETAIN | OBJC_ASSOCIATION_GETTER_AUTORELEASE
.
В OBJC_ASSOCIATION_GETTER_*
битах рассматриваются в _object_get_associative_reference
:
id _object_get_associative_reference(id object, void *key) {
id value = nil;
uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
ObjcAssociation &entry = j->second;
value = entry.value();
policy = entry.policy();
if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);
}
}
}
if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
((id(*)(id, SEL))objc_msgSend)(value, SEL_autorelease);
}
return value;
}
Так что, если вы используете OBJC_ASSOCIATION_RETAIN
, он сохранит и autorelease связанного объекта перед возвращением его к вам. Но что-то еще происходит, это не очевидно. Обратите внимание, что функция создает локальный экземпляр объекта AssociationsManager
(который является объектом C++, хранящимся в стеке). Вот определение AssociationsManager
:
class AssociationsManager {
static spinlock_t _lock;
static AssociationsHashMap *_map; // associative references: object pointer -> PtrPtrHashMap.
public:
AssociationsManager() { spinlock_lock(&_lock); }
~AssociationsManager() { spinlock_unlock(&_lock); }
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new AssociationsHashMap();
return *_map;
}
};
Таким образом, вы можете видеть, что, когда функция создает свой AssociationsManager
, он приобретает замок, который он держит, пока менеджер не будет уничтожен. Устранение происходит после функция сохранила связанный объект.
Такая же блокировка используется при установке нового связанного объекта для ключа.Эта блокировка предотвращает состояние гонки, когда один поток получает связанный объект, а другой заменяет его и заставляет объект освобождаться.
Если вы не предотвратите гонку, то когда-нибудь ваше многопоточное приложение выйдет из строя (или, что еще хуже), попытавшись получить доступ к освобожденному объекту. Вы можете использовать OBJC_ASSOCIATION_RETAIN
, чтобы предотвратить состояние гонки, или вы можете обеспечить каким-то другим способом, чтобы вы никогда не устанавливали связь в одном потоке, а получая его на другом.
Я столкнулся с этим точным состоянием гонки и ваше подробное объяснение помогло мне исправить, поэтому я вам благодарен! – khandpur
- 1. Что такое поток Безопасный атомный или неатомный?
- 2. (сохранить, неатомический) и (неатомный, сохранить) любую разницу?
- 3. Атрибуты «атомный» и «неатомный» при свойствах имеют какой-либо эффект, если вы используете пользовательский геттер/сеттер?
- 4. @property (слабый, неатомный) или @property (неатомный, слабый)? Какой из них ближе всего к рекомендациям Apple?
- 5. Атомная политика в objc_setAssociatedObject
- 6. Как работает objc_setAssociatedObject?
- 7. Использование objc_setAssociatedObject со слабыми ссылками
- 8. Проверка на атомный контекст
- 9. AtomicInteger атомный
- 10. Правильный формат ключа для objc_setAssociatedObject()
- 11. Как использовать objc_setAssociatedObject в monotouch
- 12. objc_setAssociatedObject недоступен в симуляторе iPhone
- 13. CUDA, есть ли атомный?
- 14. Неатомный доступ к атомам через объединение
- 15. Обработка исключений Django отменяет неатомный режим транзакции
- 16. Неатомный пакетный отказ в обновлении Derby
- 17. is clock_gettime() call атомный?
- 18. Асинхронный атомный массив
- 19. Basic C++ атомный массив
- 20. Параллельный атомный выбор-обновление
- 21. Атомный приращение SQL Server
- 22. Невозможно установить атомный рубиновый атомный жемчуг в рельсах 4.0
- 23. Почему putStrLn не атомный?
- 24. Атомный счетчик в gcc
- 25. Гарантированный атомный ход папки
- 26. objc_setAssociatedObject с nil для удаления - проверяется политика?
- 27. атомный приращение длинной переменной?
- 28. C++ атомный список контейнеров
- 29. Как работает атомный идеал
- 30. Как атомный_dec_if_положительный атомный?
Вероятно, это зависит от того, является ли проблема с безопасностью потока проблемой и является ли сам вызывающий объект как атомным, так и неатомным. Здесь есть большой ответ, в котором подробно описывается разница между этими двумя: http://stackoverflow.com/questions/588866/whats-the-difference-between-the-atomic-and-nonatomic-attributes –