美文网首页
iOS Category原理笔记

iOS Category原理笔记

作者: 山杨 | 来源:发表于2021-10-28 18:56 被阅读0次

通过把OC分类文件重编译为C++文件得到分类的数据结构为category_t,再到runtime源码中找到了它的结构体

  • 分类在编译之后的底层数据结构(category_t),这个结构体中包含了分类中的对象方法、类方法、属性、协议。
struct category_t {
    const char *name;
    classref_t cls;
    WrappedPtr<method_list_t, PtrauthStrip> instanceMethods;
    WrappedPtr<method_list_t, PtrauthStrip> classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
    
    protocol_list_t *protocolsForMeta(bool isMeta) {
        if (isMeta) return nullptr;
        else return protocols;
    }
};
  • 分类在程序运行的时候,rumtime会将Category的数据合并到类信息中(类对象、元类对象中)
  • 分类实现源码分析流程
void _objc_init(void) 
{
  ... 
  map_images(...)
  ...
}
/***********************************************************************
* map_images
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: write-locks runtimeLock
**********************************************************************/
void map_images(unsigned count, const char * const paths[],
           const struct mach_header * const mhdrs[]) 
{
  ...
  map_images_nolock(...)
  ...
}
void map_images_nolock(unsigned mhCount, const char * const mhPaths[],
                  const struct mach_header * const mhdrs[])
{
  ...
  _read_images(...)
  ...
}
// 读取镜像
/***********************************************************************
* _read_images 
* Perform initial processing of the headers in the linked 
* list beginning with headerList. 
*
* Called by: map_images_nolock
*
* Locking: runtimeLock acquired by map_images
**********************************************************************/
void 
_read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses) 
{
  // Discover categories. Only do this after the initial category
  // attachment has been done. For categories present at startup,
  // discovery is deferred until the first load_images call after
  // the call to _dyld_objc_notify_register completes.
  // Category discovery MUST BE Late to avoid potential races
  // when other threads call the new category code before
  // this thread finishes its fixups.
  // +load handled by prepare_load_methods()
  // Realize non-lazy classes (for +load methods and static instances)

  //发现categories。只有categories初始化拼接已经完成后才这样做。
  // 对于在启动时出现的categories
  // 发现将延迟到_dyld_objc_notify_register调用完成后的第一个load_images调用完。
  // Category发现必须延迟,以避免其他线程在此线程完成其修复之前调用新的Category代码时可能出现的竞争。
  // +load 由prepare_load_methods()处理
  // 实现非惰性类(用于+load方法和静态实例)
  for (EACH_HEADER) {
    classref_t const *classlist = hi->nlclslist(&count);
    for (i = 0; i < count; i++) {
      Class cls = remapClass(classlist[i]);
      if (!cls) continue;

      addClassTableEntry(cls);
      ...
      realizeClassWithoutSwift(cls, nil);
    }
  }
}

static Class realizeClassWithoutSwift(Class cls, Class previously)
{
  ...
  // Attach categories
  methodizeClass(cls, previously);
  ...
}

/***********************************************************************
* methodizeClass
* Fixes up cls's method list, protocol list, and property list.
* Attaches any outstanding categories.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void methodizeClass(Class cls, Class previously)
{
  ...
  // Attach categories.
  objc::unattachedCategories.attachToClass(...)
  ...
}

class UnattachedCategories
{
  ...
  void attachToClass(Class cls, Class previously, int flags)
  {
    ...
    attachCategories(...);
    ...
  }
  ...
}
// Attach method lists and properties and protocols from categories to a class.
// Assumes the categories in cats are all loaded and sorted by load order, 
// oldest categories first.
static void
attachCategories(Class cls, const locstamped_category_t *cats_list, uint32_t cats_count, int flags)
{
  ...
  class_rw_ext_t *rwe;
  prepareMethodLists(...);
  rwe->methods.attachLists(mlists, mcount);
  ...
}
static void 
prepareMethodLists(...)
{
  ...
  //将方法列表添加到数组
  //重新分配不固定的方法列表。
  //新方法被前置到方法列表数组中。
  //根据需要修复方法列表(方法排序)
  fixupMethodList(...);
  ...
}

struct class_rw_ext_t {
    DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
    class_ro_t_authed_ptr<const class_ro_t> ro;
    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;
    ...
};
// method_array_t中存放着method_list_t
// method_list_t中存放着method_t
struct method_list_t
{
  ...
}

相关文章

网友评论

      本文标题:iOS Category原理笔记

      本文链接:https://www.haomeiwen.com/subject/odspaltx.html