ios - objc_setAssociatedObject retain atomic or nonatomic -


when use objc_setassociatedobject, know whether use retain or assign, don't know how decide between objc_association_retain , objc_association_retain_nonatomic. when should 1 or other used?

executive summary: must use objc_association_retain if might call objc_setassociatedobject on 1 thread, , objc_getassociatedobject on thread, simultaneously, same object , key arguments.

gory details:

you can @ implementation of objc_setassociatedobject in objc-references.mm. difference between objc_association_retain , objc_association_retain_nonatomic matters objc_getassociatedobject.

here definitions of constants in <objc/runtime.h>:

enum {     objc_association_assign = 0,           /**< specifies weak reference associated object. */     objc_association_retain_nonatomic = 1, /**< specifies strong reference associated object.                                              *   association not made atomically. */     objc_association_copy_nonatomic = 3,   /**< specifies associated object copied.                                              *   association not made atomically. */     objc_association_retain = 01401,       /**< specifies strong reference associated object.                                             *   association made atomically. */     objc_association_copy = 01403          /**< specifies associated object copied.                                             *   association made atomically. */ }; 

note 01401 0x0301 , 01403 0x0303. source code breaks these down further:

enum {      objc_association_setter_assign      = 0,     objc_association_setter_retain      = 1,     objc_association_setter_copy        = 3,            // note:  both bits set, can test 1 bit in releasevalue below.     objc_association_getter_read        = (0 << 8),      objc_association_getter_retain      = (1 << 8),      objc_association_getter_autorelease = (2 << 8) };  

so can see objc_association_retain_nonatomic objc_association_setter_retain, objc_association_retain objc_association_setter_retain | objc_association_getter_retain | objc_association_getter_autorelease.

the objc_association_getter_* bits examined in _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 = 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; } 

so if use objc_association_retain, retain , autorelease associated object before returning you. there's else going on that's not obvious. notice function creates local instance of associationsmanager (which c++ object stored on stack). here's definition of 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;     } }; 

so can see when function creates associationsmanager, acquires lock, holds until manager destroyed. destruction happens after function has retained associated object.

the same lock used when setting new associated object key. lock prevents race condition, 1 thread getting associated object while replacing , causing object deallocated.

if don't prevent race condition, someday multithreaded app crash (or worse) trying access deallocated object. can use objc_association_retain prevent race condition, or can ensure in other way never set association on 1 thread while getting on another.


Comments

Popular posts from this blog

java - Spring Data JPA: Why findOne(id) executing delete query internally? -

python - Mongodb How to add addtional information when aggregating? -

java - Incorrect order of records in M-M relationship in hibernate -