• 0

  • 473

iOS- 类的加载(1)

6天前

1.镜像加载:read_images

_objc_init注入回调_dyld_objc_notify_register(&map_images, load_images, unmap_image) 可知镜像的加载在map_images

调用栈: map_images --> map_images_nolock --> _read_images

read_images主要功能

  • 1) 条件控制进行一次的加载
  • 2) 修复预编译阶段的 @selector 的混乱问题
  • 3) 错误混乱的类处理
  • 4) 修复重映射一些没有被镜像文件加载进来的类
  • 5) 修复一些消息
  • 6) 当我们类里面有协议的时候 : readProtocol
  • 7) 修复没有被加载的协议
  • 8) 分类处理
  • 9) 类的加载处理
  • 10) 没有被处理的类 优化那些被侵犯的类

2 类的加载

获取到classlist后进入循环,断点调试,在readclass之前打印cls,cls中没有名字,但经过readclass后再打印cls,发现cls已经有名字了,说明readclass就是类加载的关键

注:怎么找重点---- 断点调试,判断和循环里设置断点,看程序会不会进断点,如果不进,可以直接过,只关注程序的运行流程

2.1 readClass分析

断点调试

  • 定义 LGPerson
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *kc_name;
@property (nonatomic, assign) int kc_age;

- (void)kc_instanceMethod1;
- (void)kc_instanceMethod2;
- (void)kc_instanceMethod3;

+ (void)kc_sayClassMethod;

@end

NS_ASSUME_NONNULL_END



#import "LGPerson.h"

@implementation LGPerson

//+ (void)load{
//    
//}

- (void)kc_instanceMethod2{
    NSLog(@"%s",__func__);
}

- (void)kc_instanceMethod1{
    NSLog(@"%s",__func__);
}

- (void)kc_instanceMethod3{
    NSLog(@"%s",__func__);
}

+ (void)kc_sayClassMethod{
    NSLog(@"%s",__func__);
}


@end

复制代码

在main.m中调用

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LGPerson *person = [LGPerson alloc];
        [person kc_instanceMethod1];
        NSLog(@"%p",person);
    }
    return 0;
}
复制代码

在readClass函数的if和for中设置断点,重点关注类的加载部分

在readClass函数里并没有进入类的ro,rw赋值的if中,而只是类名称的关联addNamedClass和将类添加到表中addClassTableEntry

类的加载过程(ro,rw,rwe的赋值)在什么时候进行的?

2.2 realizeClassWithoutSwift(类的加载)调用时机

  • 回到_read_images函数,往函数下文看,看到一个熟悉的函数realizeClassWithoutSwift,从函数名就可知道是实现类,断点验证下---·但在_read_images中并没有调用realizeClassWithoutSwift

  • 进入到realizeClassWithoutSwift的源码中查看,确实是类的实现操作

  • 可以在 reaizeClassWithoutSwift 设置断点,并定位需要关注的类,探索什么时候调用reaizeClassWithoutSwift

  • 断点执行顺序,可知是在main函数中调用 LGPerson *person = [LGPerson alloc]之后,才调用reaizeClassWithoutSwift, 其调用堆栈为

  • reaizeClassWithoutSwift的调用时机是在消息发送的慢速查找lookUpImpOrForward中, 消息发送之前会先判断类是否实现,cls = initializeAndLeaveLocked(cls, inst, runtimeLock)----这是OC中著名的懒加载机制,将类的加载推迟到第一次方法调用的时候

问题 : 什么时候从_read_images中的realizeClassWithoutSwift函数来实现类的加载呢? 我们可以在LGPerson中实现+load函数,再断点_read_images中的realizeClassWithoutSwift函数,可以看到断点可以卡主,在进入main函数之前就进行了LGPerson类的加载

2.3 懒加载类与⾮懒加载类 — 当前类是否实现 load ⽅法

  • 懒加载类情况 数据加载推迟到第⼀次消息的时候

    调用堆栈: [LGPerson alloc] --> objc_alloc -->callAlloc --> _objc_msgSend_uncached -->lookUpImpOrForward -->initializeAndLeaveLocked-->initializeAndMaybeRelock-->realizeClassMaybeSwiftAndUnlock-->realizeClassMaybeSwiftMaybeRelock --> realizeClassWithoutSwift

  • ⾮懒加载类情况 map_images的时候 加载所有类数据 调用栈: _dyld_start --> _objc_init --> _dyld_objc_notify_register --> dyld::registerObjcNotifiers --> dyld::notityBatchPartial --> map_images -->map_images_nolock --> _read_images --> realizeClassWithoutSwift

3 methodizeClass分析

realizeClassWithoutSwift函数类的data加载完成后,会进入methodizeClass函数对方法的处理 ,关键函数调用栈:methodizeClass --> prepareMethodLists --> prepareMethodLists

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

ios

473

相关文章推荐

未登录头像

暂无评论