编写高质量代码的52个有效方法

52个有效方法(51) - 精简initialize与load的

2018-10-11  本文已影响26人  SkyMing一C

+load

源码浅析
+load方法的调用顺序图
+load
extern bool hasLoadMethods(const headerType *mhdr);
extern void prepare_load_methods(const headerType *mhdr);
 
void
load_images(const char *path __unused, const struct mach_header *mh)
{
    // Return without taking locks if there are no +load methods here.
    if (!hasLoadMethods((const headerType *)mh)) return;
 
    recursive_mutex_locker_t lock(loadMethodLock);
 
    // Discover load methods
    {
        rwlock_writer_t lock2(runtimeLock);
        prepare_load_methods((const headerType *)mh);
    }
 
    // Call +load methods (without runtimeLock - re-entrant)
    call_load_methods();
}
prepare_load_methods
void prepare_load_methods(const headerType *mhdr)
{
    size_t count, i;
    runtimeLock.assertWriting();
    classref_t *classlist = 
        _getObjc2NonlazyClassList(mhdr, &count);//获取所有类列表
    for (i = 0; i < count; i++) {
        schedule_class_load(remapClass(classlist[i]));
    }
    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
    for (i = 0; i < count; i++) {
        category_t *cat = categorylist[i];
        Class cls = remapClass(cat->cls);
        if (!cls) continue;  // category for ignored weak-linked class
        realizeClass(cls);
        assert(cls->ISA()->isRealized());
        add_category_to_loadable_list(cat);
    }
}

static void schedule_class_load(Class cls)
{
    if (!cls) return;
    assert(cls->isRealized());  // _read_images should realize
    if (cls->data()->flags & RW_LOADED) return;
 
    // Ensure superclass-first ordering
    schedule_class_load(cls->superclass);
 
    add_class_to_loadable_list(cls);
    cls->setInfo(RW_LOADED); 
}
call_load_methods
void call_load_methods(void)
{
    static bool loading = NO;
    bool more_categories;
 
    loadMethodLock.assertLocked();
 
    // Re-entrant calls do nothing; the outermost call will finish the job.
    if (loading) return;
    loading = YES;
 
    void *pool = objc_autoreleasePoolPush();
 
    do {
        // 1. Repeatedly call class +loads until there aren't any more
        while (loadable_classes_used > 0) {
            call_class_loads();
        }
 
        // 2. Call category +loads ONCE
        more_categories = call_category_loads();
 
        // 3. Run more +loads if there are classes OR more untried categories
    } while (loadable_classes_used > 0  ||  more_categories);
 
    objc_autoreleasePoolPop(pool);
 
    loading = NO;
}
call_class_loads
static void call_class_loads(void)
{
    int i;
 
    //1.获取列表
    struct loadable_class *classes = loadable_classes;
    int used = loadable_classes_used;
    loadable_classes = nil;
    loadable_classes_allocated = 0;
    loadable_classes_used = 0;
 
    //2.循环调用load方法
    for (i = 0; i < used; i++) {
        Class cls = classes[i].cls;
        load_method_t load_method = (load_method_t)classes[i].method;
        if (!cls) continue; 
 
        (*load_method)(cls, SEL_load);
    }
 
    // 3. 释放列表
    if (classes) free(classes);
}

+initialize

源码浅析
+initialize流程图
+ (void)initialize {
}
class_initialize
/***********************************************************************
* class_initialize.  Send the '+initialize' message on demand to any
* uninitialized class. Force initialization of superclasses first.
**********************************************************************/
void _class_initialize(Class cls)
{
    assert(!cls->isMetaClass());
 
    Class supercls;
    bool reallyInitialize = NO;
 
    supercls = cls->superclass;
    if (supercls  &&  !supercls->isInitialized()) {
        _class_initialize(supercls);
    }
 
    {
        monitor_locker_t lock(classInitLock);
        if (!cls->isInitialized() && !cls->isInitializing()) {
            cls->setInitializing();
            reallyInitialize = YES;
        }
    }
 
    if (reallyInitialize) {        
        _setThisThreadIsInitializingClass(cls);
 
        @try {
            callInitialize(cls);
        }
        @catch (...) {
            if (PrintInitializing) {
                _objc_inform("INITIALIZE: +[%s initialize] threw an exception",
                             cls->nameForLogging());
            }
            @throw;
        }
        @finally {
            if (!supercls  ||  supercls->isInitialized()) {
                _finishInitializing(cls, supercls);
            } else {
                _finishInitializingAfter(cls, supercls);
            }
        }
        return;
    }
    else if (cls->isInitializing()) {
        if (_thisThreadIsInitializingClass(cls)) {
            return;
        } else {
            waitForInitializeToComplete(cls);
            return;
        }
    }
    else if (cls->isInitialized()) {
 
        return;
    }
    else {
        _objc_fatal("thread-safe class init in objc runtime is buggy!");
    }
}
static void _finishInitializingAfter(Class cls, Class supercls)
{
    PendingInitialize *pending;
 
    classInitLock.assertLocked();
 
    if (PrintInitializing) {
        _objc_inform("INITIALIZE: %s waiting for superclass +[%s initialize]",
                     cls->nameForLogging(), supercls->nameForLogging());
    }
 
    if (!pendingInitializeMap) {
        pendingInitializeMap = 
            NXCreateMapTable(NXPtrValueMapPrototype, 10);
        // fixme pre-size this table for CF/NSObject +initialize
    }
 
    pending = (PendingInitialize *)malloc(sizeof(*pending));
    pending->subclass = cls;
    pending->next = (PendingInitialize *)
        NXMapGet(pendingInitializeMap, supercls);
    NXMapInsert(pendingInitializeMap, supercls, pending);
}
static void _finishInitializing(Class cls, Class supercls)
{
    PendingInitialize *pending;
    classInitLock.assertLocked();
    assert(!supercls  ||  supercls->isInitialized());
 
    if (PrintInitializing) {
        _objc_inform("INITIALIZE: %s is fully +initialized",
                     cls->nameForLogging());
    }
 
    // mark this class as fully +initialized
    cls->setInitialized();
    classInitLock.notifyAll();
    _setThisThreadIsNotInitializingClass(cls);
 
    // mark any subclasses that were merely waiting for this class
    if (!pendingInitializeMap) return;
    pending = (PendingInitialize *)NXMapGet(pendingInitializeMap, cls);
    if (!pending) return;
 
    NXMapRemove(pendingInitializeMap, cls);
 
    // Destroy the pending table if it's now empty, to save memory.
    if (NXCountMapTable(pendingInitializeMap) == 0) {
        NXFreeMapTable(pendingInitializeMap);
        pendingInitializeMap = nil;
    }
 
    while (pending) {
        PendingInitialize *next = pending->next;
        if (pending->subclass) _finishInitializing(pending->subclass, cls);
        free(pending);
        pending = next;
    }
}
- (instancetype)init
 -(instancetype)init
#if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER
    NS_DESIGNATED_INITIALIZER
#endif
    ;
- (id)init {
    return _objc_rootInit(self);
}
 
id
_objc_rootInit(id obj)
{
    return obj;
}
+ load+ initialize的异同
+ load与+ initialize的异同
要点
  1. 在加载阶段,如果类实现了load方法,那么系统就会调用它。分类里也可以定义此方法,类的load方法要比分类中的先调用。与其他方法不同,load方法不参与覆写机制。

  2. 首次使用某个类之前,系统会向其发生initialize消息。由于此方法遵从普通的覆写规则,所以通常应该在里面判断当前要初始化的是哪个类。

  3. load与initialize方法都应该实现的精简一些,这有助于保持应用程序的响应能力,也能减少引入“依赖环”的几率。

  4. 无法在编译期设定的全局常量,可以放在initialize方法里初始化。

上一篇 下一篇

猜你喜欢

热点阅读