2015-04-03 10 views
7

Nell'articolo di NSHipter su method swizzling, si dice "Swizzling dovrebbe sempre essere fatto in un dispatch_once". Perché è necessario poiché + il caricamento avviene solo una volta per classe?Utilizzo di dispatch_once nel metodo swizzling

+1

grande domanda. Non è spiegato nell'articolo e sembra eccessivo. Il carico + (vuoto) dovrebbe essere eseguito una sola volta. Non riesco a trovare alcuna risorsa che abbia un controesempio. – KirkSpaziani

+0

Penso che sia spiegato, tuttavia: * Ancora una volta, poiché lo swizzling cambia stato globale, dobbiamo prendere tutte le precauzioni a nostra disposizione nel runtime. L'atomicità è una di queste precauzioni, in quanto garantisce che il codice verrà eseguito esattamente una volta, anche attraverso diversi thread *. È un altro passo precauzionale per prevenire le condizioni di gara poiché suppongo che il metodo 'load' non garantisca necessariamente l'atomicità ma usando' dispatch_once' fa –

risposta

6

Non è necessario. +load è garantito per essere thread-safe e rientranti. Vedere 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; 
} 

Avviso il mutex ricorsiva, che garantisce che tutti i carichi sono fatte durante il blocco, e farà in modo che call_load_methods() + carico solo ottiene invocato una volta per ogni implementazione di +load.

noti che +load è speciale in quanto ci possono essere più implementazioni di esso su una base per classe, che è uno dei motivi per cui è preferito per swizzling - la vostra +load, così come l'originale +load è garantito per essere chiamato.

Bonus: Ecco la relativa documentazione sul call_load_methods() che si rivolge direttamente perché questo è thread-safe in modo che sia:

/*********************************************************************** 
* 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

Penso che l'articolo sia suggerendo che "Swizzling dovrebbe essere fatto in + carico". Ma tu puoi ancora fare swizzling da qualche altra parte. In questa situazione dovresti fare un salto in un dispatch_once per atomicità. Penso che non sia necessario avvolgere lo swizzling anche in un dispatch_once in + load.

+0

Mostrami il codice – dengApro

Problemi correlati