- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
当我使用 objc_setAssociatedObject
时,我知道是使用 retain 还是 assign,但我不知道如何在 OBJC_ASSOCIATION_RETAIN
和 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
,它会保留并自动释放关联的对象,然后再将其返回给您。但还有其他事情正在发生,但并不明显。请注意,该函数创建了 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/
在类别 UIButton .h 文件中: @interface UIButton (zz) @property (nonatomic,strong) NSString *param1; @proper
我一直这样使用 objc_setAssociatedObject(): objc_setAssociatedObject(myObject, @"myKey1", obj2, OBJC_ASSOCIA
当我使用 objc_setAssociatedObject 时,我知道是使用 retain 还是 assign,但我不知道如何在 OBJC_ASSOCIATION_RETAIN 和 OBJC_ASSO
Xcode 6.4 swift 1.2 我该怎么做? 谢谢大家 看到这个错误 最佳答案 试试这个: objc_setAssociatedObject(self, &loadOperationKey,
对类对象使用 objc_setAssociatedObject 是否正确? 我们经常用这样的静态变量来模拟类变量: Objective C Static Class Level variables但是
我正在尝试制作一个用于 objc_setAssociatedObject 的 key ,如这个问题所示: How do I use objc_setAssociatedObject/objc_getA
这个问题在这里已经有了答案: How is Associative Reference implemented? (2 个答案) 关闭 9 年前。 正如我们所知,我们可以使用类别和运行时方法在 Ob
在我接手的一个项目中,原作者选择使用 objc_setAssociatedObject(),我不是 100% 清楚它的作用或他们决定使用它的原因。 我决定查一下,不幸的是,文档并没有很好地描述它的用途
我只想向 UIView 添加一个属性,如下所示, #import "UIView+Extension.h" #import @implementation UIView (Extension) -
我正在研究向所有 UIView 实例添加属性(在本例中为整数)的方法,无论它们是否是子类。在类别中使用 objc_setAssociatedObject() 和 objc_getAssociatedO
在 3.1 SDK 中,Apple 添加了对关联对象的支持。 但是,模拟器不会编译包含对 objc_setAssociatedObject、objc_getAssociatedObject 等的引用的
如果我使用一个类别,该类别使用 objc_setAssociatedObject 向对象添加伪属性,我如何确保它们被正确释放?我是否必须在 dealloc 中手动释放它们? 最佳答案 您分配的行为决定
我知道 OBJC_ASSOCIATION_ASSIGN 存在,但如果目标对象被释放,它会将引用清零吗?或者它是否像过去那样需要将引用置为零,否则我们以后可能会面临访问错误的风险? 最佳答案 正如 ul
如果我在类别实现中使用 objc_setAssociatedObject/objc_getAssociatedObject 将模拟实例变量存储在 setter 方法中,我将如何访问 getter 方法
我想设置n Swift 中一个对象的关联对象数量 我的理解是UnsafeRawPointer的通常模式引用是这样的... static var reference = "someRef" public
import UIKit import ObjectiveC var SubRowObjectKey: String = "subRow" extension IndexPath { var
我正在尝试通过扩展向 UIView 添加点击手势支持。这使用 Objective-C 非常简单,但是当我尝试在运行时属性上设置 void 返回 block 时出现以下错误。 error: type '
在文档中... objc_setAssociatedObject Sets an associated value for a given object using a given key and a
我正在尝试使用关联对象 API 将“属性”添加到类别。 objc_setAssociatedObject(self, &kIsAnimatingAssocObjKey, animating, OBJC
我计划使用 objc_setAssociatedObject() 将 iVars 添加到类别中。但是,我不确定何时调用 objc_removeAssociatedObjects() 来删除它们。 有没
我是一名优秀的程序员,十分优秀!