iOS小知識之底層load方法的呼叫時機

語言: CN / TW / HK

小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。

1.load方法的呼叫時機?

load_images函式中 - 1.add_class_to_loadable_list:將所有主類的laod方法,收集到一張主類load方法表 - 2.add_category_to_loadable_list:將所有分類的load方法,收集到一張分類load方法表 - 3.call_class_loads:先迴圈呼叫主類的load方法 - 4.call_category_loads:再迴圈呼叫分類的load方法 如下圖所示

image-9.png

1.1 add_class_to_loadable_list

``` void add_class_to_loadable_list(Class cls) { IMP method;

loadMethodLock.assertLocked();

method = cls->getLoadMethod(); 
if (!method) return; // Don't bother if cls has no +load method

if (PrintLoading) { 
    _objc_inform("LOAD: class '%s' scheduled for +load", cls->nameForLogging()); 
}

if (loadable_classes_used == loadable_classes_allocated) {
    loadable_classes_allocated = loadable_classes_allocated*2 + 16;
    loadable_classes = (struct loadable_class *) realloc(loadable_classes, loadable_classes_allocated * sizeof(struct loadable_class));
}

loadable_classes[loadable_classes_used].cls = cls; 
loadable_classes[loadable_classes_used].method = method; 
loadable_classes_used++;

} ``` - 將所有主類的load方法,收集到一張主類load方法表

1.2 add_category_to_loadable_list

``` void add_category_to_loadable_list(Category cat) { IMP method;

loadMethodLock.assertLocked();

method = _category_getLoadMethod(cat);

// Don't bother if cat has no +load method 
if (!method) return;

if (PrintLoading) { 
    _objc_inform("LOAD: category '%s(%s)' scheduled for +load", _category_getClassName(cat), _category_getName(cat)); 
}

if (loadable_categories_used == loadable_categories_allocated) {
    loadable_categories_allocated = loadable_categories_allocated*2 + 16; 
    loadable_categories = (struct loadable_category *) realloc(loadable_categories, loadable_categories_allocated * sizeof(struct loadable_category)); 
}

loadable_categories[loadable_categories_used].cat = cat; 
loadable_categories[loadable_categories_used].method = method;
loadable_categories_used++;

} `` -add_category_to_loadable_list`:將所有分類的load方法,收集到一張分類load方法表

1.3 call_class_loads

``` static void call_class_loads(void) { int i;

// Detach current loadable list. 
struct loadable_class *classes = loadable_classes; 
int used = loadable_classes_used; 
loadable_classes = nil; 
loadable_classes_allocated = 0; 
loadable_classes_used = 0;

// Call all +loads for the detached list.
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;

    if (PrintLoading) { 
        _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging()); 
    }
    (*load_method)(cls, @selector(load)); 
}

// Destroy the detached list. 
if (classes) free(classes);

} `` -call_class_loads`:先迴圈呼叫主類的load方法

1.4call_category_loads

``` static bool call_category_loads(void) { int i, shift; bool new_categories_added = NO;

// Detach current loadable list. 
struct loadable_category *cats = loadable_categories; 
int used = loadable_categories_used; 
int allocated = loadable_categories_allocated; 
loadable_categories = nil; 
loadable_categories_allocated = 0; 
loadable_categories_used = 0;

// Call all +loads for the detached list. 
for (i = 0; i < used; i++) { 
    Category cat = cats[i].cat; 
    load_method_t load_method = (load_method_t)cats[i].method; 
    Class cls;
    if (!cat) continue;

    cls = _category_getClass(cat); 
    if (cls && cls->isLoadable()) { 
        if (PrintLoading) {
            _objc_inform("LOAD: +[%s(%s) load]\n", cls->nameForLogging(), _category_getName(cat)); 
        }
        (*load_method)(cls, @selector(load)); 
        cats[i].cat = nil; 
    }
}

// Compact detached list (order-preserving) 
shift = 0; 
for (i = 0; i < used; i++) { 
    if (cats[i].cat) { 
        cats[i-shift] = cats[i];
    } else { 
        shift++; 
    }
}
used -= shift;

// Copy any new +load candidates from the new list to the detached list. 
new_categories_added = (loadable_categories_used > 0);
for (i = 0; i < loadable_categories_used; i++) {
    if (used == allocated) { 
        allocated = allocated*2 + 16; 
        cats = (struct loadable_category *) realloc(cats, allocated * sizeof(struct loadable_category)); 
     }
     cats[used++] = loadable_categories[i]; 
 }

 // Destroy the new list.
 if (loadable_categories) free(loadable_categories);

 // Reattach the (now augmented) detached list. 
 // But if there's nothing left to load, destroy the list. 
 if (used) { 
     loadable_categories = cats;
     loadable_categories_used = used; 
     loadable_categories_allocated = allocated; 
 } else {
     if (cats) free(cats);
     loadable_categories = nil;
     loadable_categories_used = 0; 
     loadable_categories_allocated = 0;
 }

 if (PrintLoading) { 
     if (loadable_categories_used != 0) {
         _objc_inform("LOAD: %d categories still waiting for +load\n", loadable_categories_used); 
     }
 }

 return new_categories_added;

} `` -call_category_loads`:再迴圈呼叫分類的load方法