static void fb_objc_setAssociatedObject()

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);
  }