In NSHipter Artikel über method swizzling, heißt es "Swizzling sollte immer in einem dispatch_once durchgeführt werden." Warum ist das notwendig, da + Laden nur einmal pro Klasse stattfindet?Mit dispatch_once in Methode Swizzling
Antwort
Es ist nicht erforderlich. +load
ist garantiert Thread-Safe und Reentrant. Siehe 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;
}
Beachten Sie die rekursive Mutex, dass gewährleistet, dass alle Lasten beim Blocken fertig sind, und call_load_methods()
wird sichergestellt, dass + Last wird nur einmal aufgerufen pro Umsetzung +load
.
Beachten Sie, dass +load
es, dass besondere ist Grundlage mehrere Implementierungen davon auf einer Pro-Klasse sein kann, was einer der Gründe ist, warum es für Swizzling bevorzugt wird - Ihre +load
, sowie die ursprüngliche +load
garantiert sein namens.
Bonus: Hier ist die entsprechende Dokumentation auf call_load_methods()
, die direkt adressiert, warum dieses Thema in der Art und Weise sicher ist, dass es:
/***********************************************************************
* 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)
Ich denke, dieser Artikel ist schlägt vor, dass "Swizzling sollte in + load durchgeführt werden". Aber trotzdem kannst du woanders swizzeln. In dieser Situation sollten Sie in einem dispatch_once für Atomizität swizzlen. Ich denke, es ist nicht notwendig, swizzling in einem dispatch_once in + load auch zu wickeln.
Zeigen Sie mir den Code – dengApro
Große Frage. Nicht in dem Artikel erklärt und fühlt sich an wie Overkill. + (void) load sollte nur einmal ausgeführt werden. Ich kann keine Ressourcen finden, die ein Gegenbeispiel haben. – KirkSpaziani
Ich denke, es erklärt aber: * Auch, weil Swizzling globalen Zustand ändert, müssen wir alle Vorsichtsmaßnahmen zur Verfügung zu uns in der Laufzeit nehmen. Atomarität ist eine solche Vorsichtsmaßnahme, ebenso wie eine Garantie, dass Code genau einmal ausgeführt wird, sogar über verschiedene Threads hinweg. Es ist eine andere vorsorglich Rennbedingungen zu verhindern, da ich 'load' Methode denke nicht notwendigerweise Unteilbarkeit garantieren, sondern mit' dispatch_once' nicht –