通过把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
{
...
}
网友评论