Using dispatch_once in swizzling method

An NSHipter article on the swizzling method says: "Swizzling must always be executed in the manager_once." Why is this necessary, since + loading occurs only once per class?

+7
objective-c objective-c-runtime method-swizzling
source share
2 answers

This is not required. +load guaranteed to be thread safe and repeatable. See load_images in objc-runtime-new.mm :

 /*********************************************************************** * load_images * Process +load in the given images which are being mapped in by dyld. * Calls ABI-agnostic code after taking ABI-specific locks. * * Locking: write-locks runtimeLock and loadMethodLock **********************************************************************/ const char * load_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]) { BOOL found; recursive_mutex_lock(&loadMethodLock); // Discover load methods rwlock_write(&runtimeLock); found = load_images_nolock(state, infoCount, infoList); rwlock_unlock_write(&runtimeLock); // Call +load methods (without runtimeLock - re-entrant) if (found) { call_load_methods(); } recursive_mutex_unlock(&loadMethodLock); return nil; } 

Pay attention to the recursive mutex, which ensures that all loads will be executed when it is blocked, and call_load_methods() will ensure that + loading is enabled only once to implement +load .

Please note that the +load feature is that there can be many implementations for each class, which is one of the reasons why he prefers swizzling - your +load , as well as the original +load guaranteed to be called.

Bonus: here is the relevant documentation for call_load_methods() , which directly addresses why it is thread safe, so that it is:

 /*********************************************************************** * call_load_methods * Call all pending class and category +load methods. * Class +load methods are called superclass-first. * Category +load methods are not called until after the parent class +load. * * This method must be RE-ENTRANT, because a +load could trigger * more image mapping. In addition, the superclass-first ordering * must be preserved in the face of re-entrant calls. Therefore, * only the OUTERMOST call of this function will do anything, and * that call will handle all loadable classes, even those generated * while it was running. * * The sequence below preserves +load ordering in the face of * image loading during a +load, and make sure that no * +load method is forgotten because it was added during * a +load call. * Sequence: * 1. Repeatedly call class +loads until there aren't any more * 2. Call category +loads ONCE. * 3. Run more +loads if: * (a) there are more classes to load, OR * (b) there are some potential category +loads that have * still never been attempted. * Category +loads are only run once to ensure "parent class first" * ordering, even if a category +load triggers a new loadable class * and a new loadable category attached to that class. * * Locking: loadMethodLock must be held by the caller * All other locks must not be held. **********************************************************************/ void call_load_methods(void) 
+6
source share

I think the article suggests that "Swizzling should be done in + load." But still you can do something else. In this situation, you should do swizzling in dispatch_once for atomicity. I think it is not necessary to complete swizzling in dispatch_once in + load too.

+1
source share

All Articles