方法的本质: 消息 : 消息接受者 消息编号 ....参数 (消息体)
类的本质是一个带有isa属性的结构体
对象方法 储存在类,以类的实例方法使用
类方法 储存在类元类,以类的实例方法使用
LGPerson *p = [LGPerson new];
[p run];
clang编译
clang -rewrite-objc main.m -o main.cpp
int main(int argc, const char * argv[]) {
LGPerson *p = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("new"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
objc_msgSend(p, sel_registerName("run"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("walk"));
}
return 0;
}
[LGPerson new]类方法
LGPerson *p = objc_msgSend((id)objc_getClass("LGPerson"), sel_registerName("new"));
[p run]实例方法
objc_msgSend((id)p, sel_registerName("run"));
方法的本质: 消息 : 消息接受者 消息编号 ....参数 (消息体)
LGPerson类的本质是一个带有isa属性的结构体
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
#endif
struct objc_object {
Class_Nonnull isa __attribute__((deprecated));
};
对象方法 储存在类,以类的实例方法使用
类方法 储存在类元类,以类的实例方法使用
LGPerson *p = [LGPerson new];
walk方法是LGPerson的类方法
+ (void)walk{
NSLog(@"%s",__func__);
}
第一种获取 walk方法
class_getClassMethod
Method t1 = class_getClassMethod([p class], @selector(walk));
第二种获取 walk方法
object_getClass(p)
Method t2 = class_getClassMethod(object_getClass(p), @selector(walk));
第三种获取walk方法 类方法
获取元类object_getClass([p class])
储存在类元类,以类的实例方法使用 class_getInstanceMethod
Method t3 =class_getInstanceMethod(object_getClass([p class]), @selector(walk));
NSLog(@"%p----%p---%p", t1, t2, t3); // 0x10b93bc50----0x10b93bc50---0x10b93bc50
输出获取walk方法都是一样的
分类方法放在自身方法前面的
LGStudent
@implementation LGStudent
-(void)run {
NSLog(@"%s", __func__);
}
@end
LGStudent+TY
@implementation LGStudent (TY)
-(void)run {
NSLog(@"%s", __func__);
}
@end
LGStudent *st = [LGStudent new];
[strun];
控制台输出
-[LGStudent(TY) run]
runtime方法输出
unsigned int count;
// 获得方法数组
Method *methodList = class_copyMethodList([st class], &count);
// 遍历所有的方法
for (int i = 0; i < count; i++) {
// 获得方法
Method method = methodList[i];
// 获得方法名
NSString *methodName = NSStringFromSelector(method_getName(method));
NSLog(@"%@", methodName);
}
// 释放
free(methodList);
控制台输出
OCDemo1[2035:40964] run
OCDemo1[2035:40964] run
探索分类如何加载的
_objc_init -> _dyld_objc_notify_register(&map_images, load_images, unmap_image) -> map_images
-> map_images_nolock -> _read_images -> remethodizeClass -> attachCategories ->
rw->methods.attachLists(mlists, mcount) ->
{
// 1 list -> many lists
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)malloc(array_t::byteSize(newCount)));
array()->count = newCount;
if (oldList) array()->lists[addedCount] = oldList;
memcpy(array()->lists, addedLists,
addedCount *sizeof(array()->lists[0]));
}
if (oldList) array()->lists[addedCount] = oldList;
把旧的列表放在新添加的后面
分类方法放在自身方法前面的
_dyld_objc_notify_register(&map_images, load_images, unmap_image)
map_images: 管理文件中和动态库中所有的符号(class Protocol selector category) -> _read_images:
1: 加载所有类到类的gdb_objc_realized_classes表中。
2: 对所有类做重映射。 rebase (aslr) 随机地址+ 内存地址= 可访问的地址 + binding:
符号绑定,将可执行文件里面的外部链接指向 具体的实现地址
3: 将所有SEL都注册到namedSelectors表中。
4: 修复函数指针遗留。fixupMessageRef (alloc 方法== objc_alloc)
5: 将所有Protocol都添加到protocol_map表中。
6: 对所有Protocol做重映射。
7: 初始化所有非懒加载(有load方法)的类,进行rw、ro等操作。
map_images的时候加载所有类数据。
readClass -> getObjc2NonlazyClassList ->
realizeClassWithoutSwift -> methodizeClass
8:遍历已标记的懒加载(没有load方法)的类,并做初始化操作。
数据加载推迟到第一次消息的时候。
lookUpImpOrForward -> realizeClassMaybeSwiftMaybeRelock ->
realizeClassWithoutSwift -> methodizeClass
9:处理所有Category,包括Class和Meta Class。 attachCategories
10:初始化所有未初始化的类。
load_image:加载执行load方法 父类的load -> 类本身load -> 分类的load
load加载
OC中的load和initialize方法 区别
https://www.jianshu.com/p/f611aa1abf91
调用load方法时的环境很不安全,我们应该尽量减少load方法的逻辑。另一个原因是load方法是线程安全的,它内部使用了锁,所以我们应该避免线程阻塞在load方法中
load调用顺序
父类的load -> 类本身load -> 分类的load
映射文件(Mach-o文件)加载完毕之后加载load方法
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
map_images -> load_images
void call_load_methods(void)
{
...
// 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);
...
}
分类的load 最后调用
prepare_load_methods 预加载load 列表
static void schedule_class_load(Class cls)
{
..
// Ensure superclass-first ordering
schedule_class_load(cls->superclass);
add_class_to_loadable_list(cls);
...
}
schedule_class_load(cls->superclass); 确保父类优先排序
父类load 在 子类load 之前