2015-04-03 22 views
7

在NSHipter对method swizzling文章,它说:“混写应该总是在dispatch_once来完成。”为什么这是必要的,因为+加载每班只发生一次?的方法混写使用dispatch_once

+1

大问题。没有在文章中解释,感觉像是过度杀伤。 +(无效)加载只能运行一次。我找不到任何有反例的资源。 – KirkSpaziani 2015-04-03 16:24:30

+0

然而,我认为这是可以解释的:*再说一遍,因为调整会改变全局状态,所以我们需要在运行时采取一切预防措施。原子性就是这样的一种预防措施,就是保证代码只会执行一次,即使在不同的线程中也是如此*。这是防止竞争条件的另一个预防措施,因为我猜'load'方法不一定能保证原子性,但是使用'dispatch_once'确实是 – 2015-04-03 17:51:02

回答

6

它不是必需的。 +load保证是线程安全的并且是可重入的。见load_imagesobjc-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; 
} 

通知递归互斥体,即保证所有负载,同时阻止完成,call_load_methods()将确保+负载只得到每执行+load调用一次。

注意+load是在特殊的存在可以在每个阶级基础,这也是为什么它的首选混写的原因之一是多种实现 - 你+load,以及原+load是保证调用。

奖励:这里有call_load_methods()相关文件直接解决为什么这是线程安全的方式,它是:

/*********************************************************************** 
* 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's +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) 
1

我认为文章是提示说,“交叉混合应当+负载来完成”。但是你仍然可以在其他地方使用。在这种情况下,你应该在dispatch_once中调整原子性。我认为没有必要在+ load中将dispatch_once换成swizzling。

+0

让我看看代码 – dengApro 2018-01-15 07:54:47