NSThread当调用start方法的时候,start方法就会调用main方法。那么这个main方法内部做了什么呢?下面是汇编码:

 1 ;Foundation`-[NSThread main]:
2 -> 0x7fff2594fa69 <+0>: push rbp
3 0x7fff2594fa6a <+1>: mov rbp, rsp
4 0x7fff2594fa6d <+4>: mov rax, qword ptr [rdi + 0x8]
5 0x7fff2594fa71 <+8>: mov rsi, qword ptr [rax + 0x20]
6 0x7fff2594fa75 <+12>: test rsi, rsi
7 0x7fff2594fa78 <+15>: je 0x7fff2594fa8e ; <+37>
8 0x7fff2594fa7a <+17>: mov rdi, qword ptr [rax + 0x18]
9 0x7fff2594fa7e <+21>: test rdi, rdi
10 0x7fff2594fa81 <+24>: je 0x7fff2594fa8e ; <+37>
11 0x7fff2594fa83 <+26>: mov rdx, qword ptr [rax + 0x28]
12 0x7fff2594fa87 <+30>: pop rbp
13 0x7fff2594fa88 <+31>: jmp qword ptr [rip + 0x5b02d3c2] ; (void *)0x00007fff50ba4400: objc_msgSend
14 0x7fff2594fa8e <+37>: pop rbp
15 0x7fff2594fa8f <+38>: ret

因为rdi寄存器存放的就是self,我们可以知道第4行的汇编其实就是从当前NSThread对象偏移8字节,将此处地址指向的值传给rax寄存器,其实就是获取NSThread对象内部的一个实例变量值。那么NSThread对象内部偏移8字节的地方是什么实例变量呢?我们使用下面的方法获取NSThread对象内部的实例变量:

1 (lldb) po [0x600002bbe600 _ivarDescription]
2 <NSThread: 0x600002bbe600>:
3 in NSThread:
4 _private (id): <_NSThreadData: 0x600000fe0a00>
5 _bytes (unsigned char[44]): Value not representable, [44C]
6 in NSObject:
7 isa (Class): NSThread (isa, 0x7fff87b504c8)

从上面的输出可以看到,NSThread对象内部的实例变量就3个,偏移8字节就是偏移了一个isa指针的长度,那么此时的实例变量就是上面输出第4行的_NSThreadData对象,也就是说rax寄存器此时是_NSThreadData对象的地址。

继续看main的汇编码第5行,该行汇编码将_NSThreadData对象偏移32字节处的实例变量值赋给了rsi寄存器。同样,我们查看_NSThreadData对象偏移32字节是什么实例变量:

 1 po [0x600000fe0a00 _ivarDescription]
2 <_NSThreadData: 0x600000fe0a00>:
3 in _NSThreadData:
4 dict (id): <__NSDictionaryM: 0x600003edaa80>
5 name (id): @"com.apple.uikit.eventfetch-thread"
6 target (id): <UIEventFetcher: 0x6000001fc000>
7 selector (SEL): threadMain
8 argument (id): nil
9 seqNum (int): 2
10 qstate (unsigned char): Value not representable, C
11 qos (char): 33
12 cancel (unsigned char): Value not representable, C
13 status (unsigned char): Value not representable, C
14 performQ (id): nil
15 performD (NSMutableDictionary*): nil
16 attr (struct _opaque_pthread_attr_t): {
17 __sig (long): 1414022209
18 __opaque (char[56]): Value not representable, [56c]
19 }
20 tid (struct _opaque_pthread_t*): 0x600000fe0a88 -> 0x700004e45000
21 pri (double): 0.5
22 defpri (double): 0.5
23 in NSObject:
24 isa (Class): _NSThreadData (isa, 0x7fff87b504a0)

通过上面的输出,我们发现偏移32字节处是selector实例变量(计算偏移时不要忘了isa指针),也就是说现在rsi寄存器里面是selector的值。

main函数汇编第6行检测selector是否为空,为空就跳转专<+37>处,也就是汇编码第14行,此时main函数清除栈之后就会退出。如果selector有值,那么就会将_NSThreadData对象偏移24字节处的实例变量传给rdi寄存器(第8行)。对照上面的输出,就会发现rdi寄存器的值应该是target实例变量值。第9行汇编码会检测target是否为空,为空函数也会直接退出。如果不为空,就会将_NSThreadData对象偏移40字节处的实例变量传给rdx寄存器,此时rdx寄存器存储的是argument实例变量的值。有了target,有了selector,有了argument,汇编码第13行就调用objc_msgSend这个方法,调用[target selector:argument],执行完成后,main函数退出。

总结:

1 如果创建NSThread时不指定target或者selector,那么main函数就会直接推出;

2 如果都指定了,main函数会调用[target selector:argument],执行完成后退出

NSThread的main方法内部做了什么?的更多相关文章

  1. Java:关于main方法的10道面试题

    感觉假期过得好快,东西也丢得快. 假期吃喝玩乐之余也来温故一下Java知识,下面给大家整理了10道Java main方法的经典面试题,都来挑战一下自己的Java基础知识吧! 1.main方法是做什么用 ...

  2. main方法执行之前,做什么事

    1.我们知道程序的入口是main方法,那么在执行main方法之前,需要做些什么准备工作呢? 2.main方法执行之前,必须要把non-local static对象构造完成.static对象有:全局对象 ...

  3. 类(静态)变量和类(静态)static方法以及main方法、代码块,final方法的使用,单例设计模式

    类的加载:时间 1.创建对象实例(new 一个新对象时) 2.创建子类对象实例,父类也会被加载 3.使用类的静态成员时(静态属性,静态方法) 一.static 静态变量:类变量,静态属性(会被该类的所 ...

  4. 不包含适合于入口点的静态"Main"方法

    学习新建项目.此问题做为笔记. 错误 1 程序“admin.exe”不包含适合于入口点的静态“Main”方法 原因:原来创建项目的时候,用的是“空项目”,我以为这样就会生成类库,实际上,一开始准备运行 ...

  5. 07 java main方法

    1.问题:Java main方法为什么是  public static void main(String[] args)??? 序号 场景 编译 运行 解释 1 public修改为private pr ...

  6. Java中的static关键字解析(转自海子)__为什么main方法必须是static的,因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。

    Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...

  7. [Java] JVM 在执行 main 方法前的行为

    JVM 执行一个 Java 程序时,先从某个指定的 Java 类的 main 方法开始执行代码,同时,传一个字符串数组作为 main 方法的参数.例如在 Unix 系统上,执行下面的命令 java T ...

  8. 【细说Java】揭开Java的main方法神秘的面纱

    大家都知道,main方法是Java应用程序的入口,其定义格式为: public static void main(String[] args) 可是为什么要这么定义呢?不这样定义可以么?main方法可 ...

  9. 【细说Java】揭开Java的main方法神秘的面纱(转)

    大家都知道,main方法是Java应用程序的入口,其定义格式为: public static void main(String[] args) 可是为什么要这么定义呢?不这样定义可以么?main方法可 ...

  10. public static void main(String[] args){} 关于Java main()方法

    是Java程序的入口方法,JVM在运行程序时,会首先查找main()方法. public是权限修饰符,表明任何类或对象都可以访问这个方法: static表明main()方法是一个静态方法,即方法中的代 ...

随机推荐

  1. SpringBoot配置启动页(首页)控制台打印项目访问入口url

    一.SpringBootApplication 1 package com.reliable.yang; 2 3 /** 4 * @author Administrator 5 * @date 202 ...

  2. 9 CSS背景属性

    CSS 背景属性 1. background-color(背景颜色) 页面的背景颜色有四种属性值表示,分别是transparent(透明),RGB十进制颜色表示,十六进制颜色表示和颜色单词表示. 属性 ...

  3. #动态规划,组合计数,树状数组,前缀和#F 简单计数题&K 最简单的题

    先膜两位出题人 F 简单计数题 题目 有\(n\)个活动,预约期有\(k\)天,第\(j\)天YC可以获得\(a_j(1\leq a_j\leq n)\)张预约券, 他会在\(n\)个活动中等概率选择 ...

  4. OpenHarmony集成OCR三方库实现文字提取

    1. 简介 Tesseract(Apache 2.0 License)是一个可以进行图像OCR识别的C++库,可以跨平台运行 .本样例基于Tesseract库进行适配,使其可以运行在OpenAtom ...

  5. 构筑立体世界,AR Engine助力B站会员购打造沉浸式营销

    随着购物场景的逐渐多元化,越来越多电商平台把线下购物体验搬到线上,运用AR技术,跨越空间距离,帮助用户在购买前"体验"商品,增强购买意愿. 哔哩哔哩会员购(后称会员购)是B站于20 ...

  6. Excel分析师的工资能一直飙升,原因其实是...

    世界上的数据分析师分为使用Excel的分析师和其他分析师两类. 即使在互联网数据分析界,java遍街头,Python不如狗,Excel也是不可替代的. 上班前以为自己是西装笔挺的Excel数据分析师, ...

  7. HarmonyOS开发案例分享:万能卡片也能用来玩游戏

    一.前言 作为一名开发爱好者,从大了讲,我学习并进行HarmonyOS相关开发是为了能为鸿蒙生态建设尽一份绵薄之力,从小了讲,就是为了自己的兴趣.而万能卡片是一个让我非常感兴趣的东西. 很多时候我跟别 ...

  8. 润乾报表如何从 mongodb 中取数

    MongoDB 属于 NoSql 中的基于分布式文件存储的文档型数据库,是非关系数据库当中功能最丰富,最像关系数据库的.它支持的数据结构非常松散,是类似 json 的 bson 格式,因此可以存储比较 ...

  9. input 去除默认样式

    前言 如何不自己写框架,基本用不上. 正文 input{ border: 0px; background-color: none; outline: none; } input:focus{ outl ...

  10. Linux下的权限(角色,文件权限)

    目录 1.什么是权限 2.文件类型及权限 ①Linux文件类型: ②剩余9个字符对应的含义: ③文件权限值的表示方法(进制法) 3.如何操作权限 3.1改变权限的命令操作 chmod #change ...