iOS load

2021-05-18  本文已影响0人  nickNic

+load方法会在runtime加载类分类时,调用程序一启动就会调用.
每个类的,分类的load方法,在程序运行过程中只调用一次
调用顺序:
1先调用类的load
1.1按照编译先后顺序调用(先编译先调用)
1.2调用子类的load方法之前会先调用父类的load

2在调用分类的load
2.1按照编译先后顺序调用(先编译先调用)

void load_images(const char *path __unused, const struct mach_header *mh)
{
  if (!didInitialAttachCategories && didCallDyldNotifyRegister) {
      didInitialAttachCategories = true;
    loadAllCategories();
}

// 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
{
    mutex_locker_t lock2(runtimeLock);
    prepare_load_methods((const headerType *)mh);
}

// Call +load methods (without runtimeLock - re-entrant)
call_load_methods();
}
void prepare_load_methods(const headerType *mhdr)
{
size_t count, i;

runtimeLock.assertLocked();

classref_t const *classlist = 
    _getObjc2NonlazyClassList(mhdr, &count);
for (i = 0; i < count; i++) {
    schedule_class_load(remapClass(classlist[i]));
}

category_t * const *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
    if (cls->isSwiftStable()) {
        _objc_fatal("Swift class extensions and categories on Swift "
                    "classes are not allowed to have +load methods");
    }
    realizeClassWithoutSwift(cls, nil);
    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
   用递归方式先将父类先加到loadable_classes数组里面因为递归子类也会调用schedule_class_load方法
  schedule_class_load(cls->getSuperclass());
  将cls添加到loadable_classes数组最后面
  add_class_to_loadable_list(cls);
  所以loadable_classes 放入元素的位置是loadable_classes[“父类”,“子类”,“子子类”] 在结合 call_class_loads 方法不难看出为什么先调用父类的load 然后在调用子类的load
  cls->setInfo(RW_LOADED); 
}

调用load源码
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();
  先调用类的load
  do {
      // 1. Repeatedly call class +loads until there aren't any more
      while (loadable_classes_used > 0) {
          call_class_loads();
      }
      在调用分类的load
      // 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;
}
 调用类的load
 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.
  通过遍历调用类的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; 

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

  // Destroy the detached list.
  if (classes) free(classes);
}
调用分类的load
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.
  通过遍历调用分类的load方法
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));调用分类的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;
}
上一篇下一篇

猜你喜欢

热点阅读