in FBRetainCycleDetector/Associations/FBAssociationManager.mm [105:132]
static void fb_objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy) {
{
std::lock_guard<std::mutex> l(*_associationMutex);
// Track strong references only
if (policy == OBJC_ASSOCIATION_RETAIN ||
policy == OBJC_ASSOCIATION_RETAIN_NONATOMIC) {
_threadUnsafeSetStrongAssociation(object, key, value);
} else {
// We can change the policy, we need to clear out the key
_threadUnsafeResetAssociationAtKey(object, key);
}
}
/**
We are doing that behind the lock. Otherwise it could deadlock.
The reason for that is when objc calls up _object_set_associative_reference, when we nil out
a reference for some object, it will also release this value, which could cause it to dealloc.
This is done inside _object_set_associative_reference without lock. Otherwise it would deadlock,
since the object that is released, could also clean up some associated objects.
If we would keep a lock during that, we would fall for that deadlock.
Unfortunately this also means the association manager can be not a 100% accurate, since there
can technically be a race condition between setting values on the same object and same key from
different threads. (One thread sets value, other nil, we are missing this value)
*/
fb_orig_objc_setAssociatedObject(object, key, value, policy);
}