登陆 | 注册 设为首页 | 加入收藏 | 联系我们
太和养老网
热词老年艺术  助老机构  养老系统  

中心区域北京 天津 河北 山西 内蒙古 辽宁 吉林 黑龙江 上海 江苏 浙江 安徽 福建 江西 山东 河南 湖北 湖南 广东 广西 海南 重庆 四川 贵州 云南 西藏 陕西 甘肃 青海 宁夏 新疆 香港 澳门 台湾 全国城市养老院目录 全国县市养老院汇总目录 太和AI作品展 太和养老艺术网AI作品展示

Runtime底层原理--IMP查找流程、动态方法解析、消息转发源码分析-飞

 

2023/7/6 17:11:30 ('互联网')

Runtime底层原理

了解了Runtime函数含义,我们就可以直接使用Runtime的API了,那接下来继续探究Runtime的源码,经过源码分析来更加深刻的了解Runtime原理。

开发应用

都知道Runtime很重要,但是有很多小伙伴根本不了解,或者只是知道可以替换方法啊、可以交换两个方法的调用,项目中也用不到,
从进入iOS开始,写了无数个[[objc alloc] init],这个到底在干嘛?初始化和init?alloc和init到底做了什么?

通过汇编查看方法调用
        Person *person = [Person alloc];        Person *person1 = [person init];        Person *person2 = [person init];        NSLog(@"%p-----%p------%p", person, person1, person2);

这里会输出什么呢?

0x10102e1a0-----0x10102e1a0------0x10102e1a0

来,让我们断点看下,allocinit是怎么调用的

objc_msgSend

我们看到调用allocinit都调起了objc_msgSend,接下来跟着符号断点走

libobjccallAlloc

进入libobjc库的dylib之后走+[NSObject alloc]方法,指针调起_objc_rootAlloc,进入_objc(会者定离一期一祈是啥意思?会者定离,一期一祈是指经常会面的人必有离散之时。意思是说世事无常,没有不散的宴席。这两句话总的来说,就是说世事无常,当珍惜遇见的人,把和每个人相遇,当作一生只有一次的缘分。)_rootAlloc方法,继续调起callAlloc,通过寄存器,可以看到alloc已经通过类创建实例对象

类对象

init按照同样方法 依然可以通过汇编看出方法调用顺序,可以用真机进行测试并打印

通过编译C++

当新的对象被创建时,其内存同时被分配,实例变量也同时被初始化。对象的第一个实例变量是一个指向该对象的类结构的指针,叫做 isa。通过该指针,对象可以访问它对应的类以及相应的父类。在 Objective-C 运行时系统中对象需要有 isa 指针,我们一般创建的从 NSObject 或者 NSProxy 继承的对象都自动包括 isa 变量。接下来看下对象被创建的过程
首先,我们通过clang命令

$$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o testMain.c++

也可以用clang -rewrite-objc main.m -o test.c++命令,只不过会有很多警告、代码会更长(大概9万多行)。
编译main函数中的OC代码为C++代码

int main(int argc, const char * argv[]) {    @autoreleasepool {                Person *p = [[Person alloc] init];        [p run];      }    return 0;}

编译后多一个testMain.c++文件,打开后在代码最后面会发现我们的main函数

int main(int argc, const char * argv[]) {    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;         Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));        ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));    }    return 0;}

可以看出,我们的方法调用会编译成objc_msgSend,

person对象

由此还会发现对象的本质其实就是一个结构体

下层通讯(通过源码查看objc_msgSend内部实现)

首先我们到苹果open source官网下载最新源码

源码

在方法调用的时候,会发送objc_msgSend消息,objc_msgSend会根据sel找到函数实现的指针imp,进而执行函数,那sel是如何找到imp的呢?
objc_msgSend在发送消息时候根据sel查找imp有两种方式

快速(通过汇编的缓存快速查找)慢速(C配合C++、汇编一起查找)
先看下objc_classobjc_class

bits中包含各种数据,cache(每个类都有一个)用来存储方法select和imp,select和imp会以哈希表形式存在
objc_msgSend在快速查找的时候,就是通过汇编查找objc_class中的cache,如果找到则直接返回,否则通过C的lookup,找到后再存入cache

汇编部分快速查找

首先调用objc_msgSend会走到ENTRY

ENTRY

先判断p0检查是否为空和tagged pointer(特殊类型)判断,调用LNilOrTagged进行isa处理,通过isa找到相应类class,最后调用LGetIsaDone来执行CacheLookup在缓存中查找imp,如果查找到直接调起imp否则调起objc_msgSend_uncached,objc_msgSend_uncached有两种情况

CacheLookup

首先,第一个是CacheHit,直接调起imp,第二个是CheckMiss,之后调用objc_msgSend_uncached,第三个就是add,下面是CacheHit和CheckMiss的宏

CacheLookup macro

那如果在缓存中没有查找到imp,调起objc_msgSend_uncached,在方法列表中找到imp之后再TailCallFunctionPointer调起imp

    STATIC_ENTRY __objc_msgSend_uncached    UNWIND __objc_msgSend_uncached, FrameWithNoSaves    // THIS IS NOT A CALLABLE C FUNCTION    // Out-of-band p16 is the class to search        MethodTableLookup      // 方法列表中找到imp    TailCallFunctionPointer x17

重点:MethodTableLookup是怎么操作的

小知识点:通过method list查找method,下面是method_t的结构,method其实是一个哈希表,sel和imp是键值对

struct method_t {    SEL name;    const char *types;       // 参数类型    MethodListIMP imp;    struct SortBySELAddress :        public std::binary_function<const method_t&,                                    const method_t&, bool>    {        bool operator() (const method_t& lhs,                         const method_t& rhs)        { return lhs.name <



扫码加微信详细咨询太和智慧养老产品和平台服务!

 

 





版权声明:

---------------------------------------------------------------


所有信息来源于互联网,本文的版权归原作者所有,不代表本网观点和立场。

本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请发送邮件至 81480447@qq.com 举报,一经查实,本站将立刻删除。



扫码加微信详细咨询太和智慧养老产品和平台服务!

 

养老资讯
助老机构介绍
评论
已有 0 条评论

最新评论

推荐养老院

您希望养老院位于
  • 不限
  • 东城
  • 西城
  • 崇文
  • 宣武
  • 朝阳
  • 丰台
  • 石景山
  • 海淀
  • 门头沟
  • 房山
  • 通州
  • 顺义
  • 昌平
  • 大兴
  • 怀柔
  • 平谷
  • 延庆
  • 密云
您希望的价格范围
  • 不限
  • 500以下
  • 500-1000
  • 1000-2000
  • 2000-3000
  • 3000-5000
  • 5000以上
老人的情况是
  • 不限
  • 自理
  • 半自理
  • 全护理
  • 特护

姓名

年龄

电话

全国城市养老院



关于我们 | 联系方式 | 网站地图 | 友情链接

Copyright 2010-2022 京ICP备18035644号-3 北京太和 版权所有