我们先来定义三个NSString

-(void) testNSString
{
NSString* a = @"abc";
NSString* b = [NSString stringWithUTF8String:"abc"];
NSString* c = [@"ab" stringByAppendingString:@"c"];
}

大家都明白,a, b, c 都equalsToString:@"abc"。但是它们是指向同一个对象实例呢,还是根本就不是同一种类型。我们来看一下反汇编代码:

function_args`-[ViewController testNSString]:
0x10bd48590 <+>: pushq %rbp
0x10bd48591 <+>: movq %rsp, %rbp
0x10bd48594 <+>: subq $0x40, %rsp
0x10bd48598 <+>: leaq 0x1ac9(%rip), %rax ; @"abc"
0x10bd4859f <+>: movq %rdi, -0x8(%rbp) ; // save %rdi
0x10bd485a3 <+>: movq %rsi, -0x10(%rbp) ; // save %rsi
0x10bd485a7 <+>: movq %rax, %rdi
0x10bd485aa <+>: callq 0x10bd48b1c ; symbol stub for: objc_retain
0x10bd485af <+>: leaq 0x616(%rip), %rdx ; "abc"
0x10bd485b6 <+>: movq %rax, -0x18(%rbp) ; // NSString* a
-> 0x10bd485ba <+>: movq 0x277f(%rip), %rax ; (void *)0x000000010c05db20: NSString // (Class)$rax = NSString
0x10bd485c1 <+>: movq 0x2730(%rip), %rsi ; "stringWithUTF8String:"
0x10bd485c8 <+>: movq %rax, %rdi
0x10bd485cb <+>: callq 0x10bd48b0a ; symbol stub for: objc_msgSend
0x10bd485d0 <+>: movq %rax, %rdi
0x10bd485d3 <+>: callq 0x10bd48b28 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x10bd485d8 <+>: leaq 0x1aa9(%rip), %rdx ; @"ab"
0x10bd485df <+>: leaq 0x1ac2(%rip), %rsi ; @"'c'"
0x10bd485e6 <+>: movq %rax, -0x20(%rbp) ; // NSString* b
0x10bd485ea <+>: movq 0x270f(%rip), %rax ; "stringByAppendingString:"
0x10bd485f1 <+>: movq %rdx, %rdi ; // lea 0x1aa9(<+79>) -> %rdx -> %rdi
0x10bd485f4 <+>: movq %rsi, -0x40(%rbp)
0x10bd485f8 <+>: movq %rax, %rsi ; // lea 0x270f(<+97>) -> %rax -> %rsi
0x10bd485fb <+>: movq -0x40(%rbp), %rdx ; // 0x1ac2(<+86>) -> %rsi -> -0x40(%rbp) -> %rdx
0x10bd485ff <+>: callq 0x10bd48b0a ; symbol stub for: objc_msgSend
0x10bd48604 <+>: movq %rax, %rdi
0x10bd48607 <+>: callq 0x10bd48b28 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x10bd4860c <+>: movq %rax, -0x28(%rbp) ; // NSString* c
0x10bd48610 <+>: movq -0x18(%rbp), %rax
0x10bd48614 <+>: movq %rax, %rdi
0x10bd48617 <+>: callq 0x10bd48b22 ; symbol stub for: objc_retainAutorelease

NSString* a = @"abc"; 的反汇编片段如下:

    0x10bd48598 <+>:   leaq   0x1ac9(%rip), %rax        ; @"abc"
0x10bd4859f <+>: movq %rdi, -0x8(%rbp) ; // save %rdi
0x10bd485a3 <+>: movq %rsi, -0x10(%rbp) ; // save %rsi
0x10bd485a7 <+>: movq %rax, %rdi
0x10bd485aa <+>: callq 0x10bd48b1c ; symbol stub for: objc_retain
0x10bd485b6 <+>: movq %rax, -0x18(%rbp) ; // NSString* a

如大家所知,@"abc"是一个全局实例,并且对其retain了一次(,因为是ARC环境),然后由a指向了它。

剩下的b和c却是从stringXXX调用中返回的,到底返回了什么,在没有调试过之前,你我都不好一口定金说它返回的就是什么。好就由调试器lldb告诉我们。

0x7fff53eb59a8: 0x00007fce7b706230            // NSString* c  {retainCount:, hash:} (__NSCFString *)
0x7fff53eb59b0: 0xa000000006362613 // NSString* b {retainCount:-, hash:} (NSTaggedPointerString *)
0x7fff53eb59b8: 0x000000010bd4a068 // NSString* a {retainCount:-, hash:} (__NSCFConstantString *)

你断言对了吗?lldb给我们的信息真不少,真是可靠的小伙伴。

首先三者指向的目标不一样。

第二retainCount唯独c是可数的,表明它们生命周期不同。

第三它们的hash一致,表明它们的内容一样。

最后真真切切打印,它们不同类,是同宗。

我们先分析指针,第一列绿字地址,表明a,b,c是在堆栈中指针变量,而且地址相邻,和我的定义代码一致。然后看第二列地址,是a,b,c分别指向的地址,c指向堆栈下向某处,没错那就是堆;而b是一个无理头地址,看过我上一篇的介绍就会知道这是一个tagged指针;至于a中规中矩说出它就是全局实例。

原来a,b,c都不是同一样实例。但是结论可能定得太早。

现在我们再来分析它们的生命周期,它们的生命周期受谁掌控。c毫无疑问是受retain/release控制的。然而a,b岂不在retain的时候就被dealloc? 通过反汇编跟踪b@tagged指针忽略retain/release,a@__NSCFConstantString的retain/release不做任何处理。表明了a,b是与程序一样长寿的寿星公。那么这两位寿星公的关系几何呢,它们有上一腿吗?你会怀疑它们是同一身份吗?

不要净是我在说,如果你还不知道真相的话,也有兴趣弄明白就请阁下亲自验证一下了。

最后我们看一下lldb给出的NSString的类的父子链

NSString
NSMutableString
__NSCFString
__NSCFConstantString
NSString
NSTaggedPointerString

另外要清楚一点,objc中的继承是接口继承,不一定是成员继承,大家都知道声明都用@interface,class是可以动态构造的。

最后,又一次多谢大家的观看,更多的objc分析请关注后面的文章。

下一篇大家将会看到幽灵一样的指针TaggedPointer。

反汇编分析NSString,你印象中的NSString是这样吗的更多相关文章

  1. 九、Foundation框架中的NSString常用方法

    一.NSString的创建 方式1创建常量字符串 NSString *st = @"this is string!"; //这种方式创建的字符串不需要释放 方式2创建空字符串,给予 ...

  2. (转载)OC学习篇之---Foundation框架中的NSString对象和NSMutableString对象

    在之前的一篇文章中我们说到了Foundation框架中的NSObject对象,那么今天在在来继续看一下Foundation框架中的常用对象:NSString和NSMutableString. 在OC中 ...

  3. OC学习篇之---Foundation框架中的NSString对象和NSMutableString对象

    今天在在来继续看一下Foundation框架中的常用对象:NSString和NSMutableString 在OC中NSString对象是不可变的,和Java中的String一样的,而NSMutabl ...

  4. objc反汇编分析,block函数块为何物?

    上一篇向大家介绍了__block变量的反汇编和它的伪代码,本篇函数块block,通常定义成原型(^){},它在反汇编中是什么东西. 我们先定义将要反汇编的例子,为减少篇幅例子采用non-arc环境. ...

  5. Linux下简单C语言小程序的反汇编分析

    韩洋原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 写在开始,本文为因为参加MOO ...

  6. 反汇编分析objc函数枢纽objc_msgSend

    在分析objc_msgSend之前,先来搞清楚另一个问题. 函数是什么?可能会答 void foo(void) {} 像这样就是一个函数.或者函数包括函数原型和函数定义,是一段执行某样功能的机器代码. ...

  7. Hbase源码分析:Hbase UI中Requests Per Second的具体含义

    Hbase源码分析:Hbase UI中Requests Per Second的具体含义 让运维加监控,被问到Requests Per Second(见下图)的具体含义是什么?我一时竟回答不上来,虽然大 ...

  8. 深度分析如何在Hadoop中控制Map的数量

    深度分析如何在Hadoop中控制Map的数量 guibin.beijing@gmail.com 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数 ...

  9. 零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里

    原文:零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里 本章将教大家如何在Blend 4里新增Media El ...

随机推荐

  1. 7.Linux文件编辑之Vim

    1.VIM基本概述 1.什么是VIM? vi和vim是Linux下的一个文本编辑工具.(可以理解为windows的记事本,或word文档) 2.为什么要使用VIM? 因为Linux系统一切皆为文件,而 ...

  2. unity text实现鼠标光标

    由于项目需求,需要在text上实现鼠标的cursor,并且随着点击位置cursor移动.实现方法: 1)新建一个光标的prefab(简单为之,直接在image中添加一个竖线spirte),增加脚本控制 ...

  3. Spring框架学习笔记(6)——阿里云服务器部署Spring Boot项目(jar包)

    最近接外包,需要部署服务器,便是参考了网上的几篇博文,成功在阿里云服务器成功部署了Spring Boot项目,特记下本篇笔记 Spring Boot项目打包 这里说一下部署的一些问题 1.mysql驱 ...

  4. IL2CPP深入详解-总览

    导语 该系列将会分为以下几个部分:1. 总览(本文)2. c++代码解析3. 调试c++代码4. 方法调用(一般方法,虚方法等)5. 泛型共享6. 类型与方法的 P/invoke 封装7. 垃圾回收8 ...

  5. "Dependency on app with no migrations: %s" % key[0]

    问题描述:我在model中建好模型类,运行的控制台就报错误: 解决方法:1,首先需要在setting中重载AUTH_USER_MODEL AUTH_USER_MODEL = 'users.UserPr ...

  6. Linux的目录介绍

    Linux的目录介绍 Linux系统以目录来组织和管理系统中的所有文件.Linux系统通过目录将系统中所有的文件分级.分层组织在一起,形成了Linux文件系统的树型层次结构.以根目录 “/” 为起点, ...

  7. [2018-08-03] python开发个人资源共享网--第一天

    项目需求-环境搭建 python版本:python 3.6.2 开发工具:PyCharm 数据库:MySql5.7.24 数据库管理工具:Navicat 环境搭建完毕 ---------------- ...

  8. Redis开发与运维:SDS

    STRING 我们会经常打交道的string类型,在redis中拥有广泛的使用.也是开启redis数据类型的基础. 在我最最开始接触的redis的时候,总是以为字符串类型就是值的类型是字符串. 比如: ...

  9. CSPS模拟 57

    rank4大众rank T1 天空龙 让他自由翱翔吧 T2 巨神兵 对于n=10的测试点本可以打出非常优秀的分层状压 但是没有打出来,因为对拓扑图理解不够深刻,纠结于指回的边,实际上只关注伸出的边就可 ...

  10. CSPS模拟 41

    说不会鸽就不会鸽的 虽然是炸裂的一场 T1没读懂题,T23交了两个无脑暴力 (公式懒得打了 latex过于感人) T1 点阵内不重合的直线有多少条? 枚举斜率,那么“后继”不在点阵内的点可以作出一个贡 ...