7

NSHipter のメソッド スウィズリングに関する記事では、「スウィズリングは常に dispatch_once で実行する必要があります」と書かれています。+load はクラスごとに 1 回しか発生しないため、なぜこれが必要なのですか?

4

2 に答える 2

6

必須ではありません。+loadスレッドセーフで再入可能であることが保証されています。で参照load_imagesしてください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;
}

ブロック中にすべてのロードが行わcall_load_methods()れることを保証し、+load が の実装ごとに 1 回だけ呼び出されることを保証する再帰的ミューテックスに注意してください+load

は、クラスごとに複数の実装が存在する可能性があるという点で特別であることに注意してください。これが、+loadスウィズリングに好まれる理由の 1 つです。+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)
于 2015-07-31T03:07:11.907 に答える
1

その記事は「スウィズリングは +load で行うべき」ということを示唆していると思います。それでも、他の場所でスウィズリングを行うことはできます。この状況では、原子性のためにdispatch_onceでスウィズリングを行う必要があります。+loadでもdispatch_onceでスウィズリングをラップする必要はないと思います。

于 2015-07-31T02:51:03.663 に答える