gpt4 book ai didi

ios - objc_setAssociatedObject 保留原子或非原子

转载 作者:可可西里 更新时间:2023-11-01 06:21:34 25 4
gpt4 key购买 nike

当我使用 objc_setAssociatedObject 时,我知道是使用 retain 还是 assign,但我不知道如何在 OBJC_ASSOCIATION_RETAINOBJC_ASSOCIATION_RETAIN_NONATOMIC 之间做出决定>。什么时候应该使用其中之一?

最佳答案

执行摘要:您必须使用 OBJC_ASSOCIATION_RETAIN如果你可以调用objc_setAssociatedObject在一个线程上,和objc_getAssociatedObject在另一个线程上,同时使用相同的 objectkey参数。

血淋淋的细节:

可以看看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. */
};

请注意 014010x0301014030x0303 .源代码进一步分解了这些:

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 ,它会保留并自动释放关联的对象,然后再将其返回给您。但还有其他事情正在发生,但并不明显。请注意,该函数创建了 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 时,它获得一个锁,它持有直到管理器被销毁。销毁发生在函数保留关联对象之后。

为 key 设置新的关联对象时使用相同的锁。此锁可防止竞争条件,在这种情况下,一个线程正在获取关联的对象,而另一个线程正在替换它并导致对象被释放。

如果您不阻止竞争条件,那么总有一天您的多线程应用程序会因尝试访问已释放的对象而崩溃(或更糟)。您可以使用 OBJC_ASSOCIATION_RETAIN以防止竞争条件,或者您可以通过某种其他方式确保永远不会在一个线程上设置关联而在另一个线程上获取关联。

关于ios - objc_setAssociatedObject 保留原子或非原子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29934289/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com