關(guān)于孫源那道經(jīng)典iOS面試題目的疑問

今天我們來說一下關(guān)于孫源之前提出的那道經(jīng)典面試題.
題目如下:

@interface FJFPerson : NSObject
// name
@property (nonatomic, copy) NSString *name;
- (void)print;
@end

@implementation FJFPerson
- (void)print {
    NSLog(@"my name is %@", self.name);
}
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    
    id cls = [FJFPerson class];
    void *obj = &cls;
    [(__bridge id)obj print];
}

打印出來的結(jié)果為:

2019-10-02 19:13:52.387769+0800 FJFRuntimeInterviewQuestionDemo[16143:509566] my name is <ViewController: 0x7ff0aac05df0>
打印結(jié)果.png

對于這個打印結(jié)果,我們先來說一下,之前比較官方的解釋,然后我們再來說一下對于這個解釋的疑問。

關(guān)于這個解釋這篇文章也解釋很清楚:

一道值得思考的iOS面試題

不同的是片仿,我是通過匯編來解釋堆棧關(guān)系,而我這邊的重點是在第二部分尤辱,如果對于這個解釋已經(jīng)了解砂豌,可以直接看第二部分

一.結(jié)果的官方解釋

A.為什么不會崩潰

  • id cls = [FJFPerson class];這句代碼里面的cls指向的是FJFPerson這個類光督。

  • void *obj = &cls;然后在這里obj是一個指向cls的指針阳距。

  • 而通過如下源碼:

struct objc_object {
private:
    isa_t isa;
}
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;
}

我們可以看出這里objc_object這個對象的首字段是isa指向一個Class

也就是說结借,這里的obj就相當(dāng)于一個FJFPerson實例對象的指針筐摘,指向了cls,而cls就相當(dāng)于isa指針,指向了FJFPerson類船老。

如下圖所示:

對照圖.png
  • [(__bridge id)obj print];所以這里調(diào)用就相當(dāng)于FJFPerson實例對象的調(diào)用[person print]咖熟,是能夠正常調(diào)用

B.為什么打印出ViewController對象

    1. 我們在FJFPersonprint添加self&_name的地址信息
@implementation FJFPerson
- (void)print {
    NSLog(@"self: %p", self);
    NSLog(@"self.name: %p", &_name);
    
    NSLog(@"my name is %@", self.name);
}
@end

打印結(jié)果如下:

地址信息.png

從這個地址信息,我們可以看出selfname之間的地址差8個字節(jié)柳畔,即1個指針的距離.

  • 而在id cls = [Spark class];前面添加代碼NSString *str = @"11111"; NSLog(@"cls address:%p str address:%p",&cls,&str);, 打印出如下信息:
地址對照圖.png

可以看出:

  • cls的地址比str的地址值大8個字節(jié)馍管。
  • self.namestr的地址值一樣,指向字符串11111

因為函數(shù)調(diào)用采用棧的形式薪韩,棧的地址是從高地址到低地址确沸,所以先入棧的strcls8個字節(jié),而print函數(shù)里面的self地址和cls地址一致俘陷,是因為[obj print]的是通過clsisa來進行方法調(diào)用罗捎,所以self就是obj,而self.name的地址由于大self地址8個字節(jié),所以self.name的地址剛好和str地址一致拉盾。

也就是說這里棧參數(shù)的數(shù)據(jù)結(jié)構(gòu)格式桨菜,對應(yīng)了obj對象地址的數(shù)據(jù)結(jié)構(gòu)。

2. 至于為什么打印的是ViewController對象:

從上面分析我們可以看出self.name的值是在cls之前入棧的值捉偏,與cls相差8個字節(jié)雷激,因此我們通過匯編分析下堆棧信息:

FJFRuntimeInterviewQuestionDemo`-[ViewController viewDidLoad]:
    0x10f8b10d0 <+0>:   pushq  %rbp 
    0x10f8b10d1 <+1>:   movq   %rsp, %rbp 
    0x10f8b10d4 <+4>:   subq   $0x40, %rsp                - rsp - 0x40 ->開辟64個字節(jié)椞媸撸空間 
    0x10f8b10d8 <+8>:   movq   %rdi, -0x8(%rbp)           -  <ViewController: 0x7fd291512f90> 將self的值 給(rdp - 0x8) 
    0x10f8b10dc <+12>:  movq   %rsi, -0x10(%rbp)          -  rsi的 “viewDidLoad”告私, 將self的值給rdp - 0x10 
    0x10f8b10e0 <+16>:  movq   -0x8(%rbp), %rsi           -  將self的值給rsi 
    0x10f8b10e4 <+20>:  movq   %rsi, -0x20(%rbp)          - 將rsi的值給self給 內(nèi)存地址(rdp-0x20) 
    0x10f8b10e8 <+24>:  movq   0x2e39(%rip), %rsi        ; (void *)0x000000010f8b3f40: ViewController 將”ViewController”字符串地址給rsi 
    0x10f8b10ef <+31>:  movq   %rsi, -0x18(%rbp)          - 將”ViewController”字符串的地址給(rbp - 0x18) 
    0x10f8b10f3 <+35>:  movq   0x2d7e(%rip), %rsi        ; “viewDidLoad" 將viewDidLoad的字符串地址給rsi 
    0x10f8b10fa <+42>:  leaq   -0x20(%rbp), %rdi          - 將內(nèi)存地址(rbp-0x20)的地址給rdi 
    0x10f8b10fe <+46>:  callq  0x10f8b184e              ; symbol stub for: objc_msgSendSuper2 跳轉(zhuǎn)到objc_msgSendSuper2命令 
    0x10f8b1103 <+51>:  movq   0x2de6(%rip), %rsi        ; (void *)0x000000010f8b4008: FJFPerson 將文本地址給rsi 
    0x10f8b110a <+58>:  movq   0x2d6f(%rip), %rdi        ; “class” 將"class”給rdi 
    0x10f8b1111 <+65>:  movq   %rdi, -0x38(%rbp)         - 將rdi(“class”)的值給(rbp-0x38) 
    0x10f8b1115 <+69>:  movq   %rsi, %rdi                - 將rsi(“FJFPerson”)給rdi 
    0x10f8b1118 <+72>:  movq   -0x38(%rbp), %rsi         - 將(rbp-0x38)的值給rsi 
    0x10f8b111c <+76>:  callq  *0x1ee6(%rip)             ; (void *)0x00007fff503b1780: objc_msgSend 調(diào)用objc_msgSend方法 
    0x10f8b1122 <+82>:  movq   %rax, %rdi                - 將返回值給rdi 
    0x10f8b1125 <+85>:  callq  0x10f8b185a              ; symbol stub for: objc_retainAutoreleasedReturnValue 
    0x10f8b112a <+90>:  movq   %rax, -0x28(%rbp)        - 將cls返回值給(rbp-0x28) 
->  0x10f8b112e <+94>:  leaq   -0x28(%rbp), %rax        將rbp-0x28地址給rax 
    0x10f8b1132 <+98>:  movq   %rax, -0x30(%rbp)        將rax的值(obj)給(rbp-0x30) 
    0x10f8b1136 <+102>: movq   -0x30(%rbp), %rdi         將(rbp-0x30)的值給rdi 
    0x10f8b113a <+106>: movq   0x2d47(%rip), %rsi        ; “print” 將print給rsi 
    0x10f8b1141 <+113>: callq  *0x1ec1(%rip)             ; (void *)0x00007fff503b1780: objc_msgSend 進行print函數(shù)調(diào)用 
當(dāng)前棧.png

經(jīng)過匯編的分析屎暇,我們很容易看出cls的之前入棧的是selfviewController本身。

以上就是官方給出的分析驻粟,我們總結(jié)一下:

所有NSObject對象的首地址都是指向這個對象的所屬類根悼,反過來說如果一個地址指向某個類,我們可以把這個地址當(dāng)做對象去用蜀撑。所以編譯可以通過挤巡,進行方法調(diào)用也不會報錯。

打印結(jié)果是ViewController對象的原因是因為cls在棧上的數(shù)據(jù)結(jié)構(gòu)符合它作為真實類的數(shù)據(jù)結(jié)構(gòu)酷麦,self.name的地址正好是self對象的地址.

二. 存在的疑問

大家都知道:

arm64架構(gòu)之前矿卑,isa就是一個普通的指針,存儲著class沃饶、Meta-Class對象的內(nèi)存地址母廷。
arm64架構(gòu)開始,對isa進行了優(yōu)化糊肤,變成了一個共用體(union)結(jié)構(gòu)琴昆,還使用位域來存儲更多的信息。

isa.jpg

也就是說在arm64架構(gòu)中馆揉,一個實例對象比如personisa指針并沒有直接指向FJFPerson類业舍,而是需要isa地址和相應(yīng)架構(gòu)的ISA_MASK掩碼進行相與,才能得到真正的指向FJFPerson類的地址升酣。

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL

接下來我們再來分析下調(diào)用的方法:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    id cls = [FJFPerson class];
    
    void *obj = &cls;
    [(__bridge id)obj print];

}
  • id cls = [FJFPerson class];這句代碼里cls是指向FJFPerson類的指針
  • void *obj = &cls;這里的obj是一個二級指針舷暮,是指向cls的的指針,也就是說obj里面存儲的就是一個單純的cls地址值,并非是個共用體
  • [(__bridge id)obj print];這里是進行一個消息的發(fā)送

我們將ViewController.m轉(zhuǎn)換為C++代碼看一下:

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m -o ViewController.cpp

我們可以看到如下C++代碼:

static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));

    id cls = ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("FJFPerson"), sel_registerName("class"));

    void *obj = &cls;
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("print"));

}

我們可以看出這里是直接對obj進行print的消息發(fā)送噩茄。

接下來我們看下objc_msgSendarm64架構(gòu)上的源碼:

/********************************************************************
 *
 * id objc_msgSend(id self, SEL _cmd, ...);
 * IMP objc_msgLookup(id self, SEL _cmd, ...);
 * 
 * objc_msgLookup ABI:
 * IMP returned in x17
 * x16 reserved for our use but not used
 *
 ********************************************************************/
    .data
    .align 3
    .globl _objc_debug_taggedpointer_classes
_objc_debug_taggedpointer_classes:
    .fill 16, 8, 0
    .globl _objc_debug_taggedpointer_ext_classes
_objc_debug_taggedpointer_ext_classes:
    .fill 256, 8, 0
    ENTRY _objc_msgSend
    UNWIND _objc_msgSend, NoFrame
    MESSENGER_START
    cmp x0, #0          // nil check and tagged pointer check 檢查x0即isa是否為nil或者tagged Pointer
    b.le    LNilOrTagged        //  (MSB tagged pointer looks negative) 如果為nil或者tagged Pointer 就跳轉(zhuǎn)到 LNilOrTagged
    ldr x13, [x0]       // x13 = isa  將isa的值給x13
    and x16, x13, #ISA_MASK // x16 = class   將isa與isa_mask進行與操作得到相關(guān)的類地址
LGetIsaDone:
    CacheLookup NORMAL      // calls imp or objc_msgSend_uncached 進入正常的緩存方法查找
LNilOrTagged:
    b.eq    LReturnZero     // nil check nil的檢測
    // tagged
    mov x10, #0xf000000000000000
    cmp x0, x10
    b.hs    LExtTag
    adrp    x10, _objc_debug_taggedpointer_classes@PAGE
    add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
    ubfx    x11, x0, #60, #4
    ldr x16, [x10, x11, LSL #3]
    b   LGetIsaDone

通過源碼我們可以分析:

[(__bridge id)obj print];這句代碼走到源碼里面,源碼取obj存儲的地址下面,也就是cls的地址跟ISA_MASK進行相與,我們會發(fā)現(xiàn)巢墅,cls的地址與ISA_MASK相與后的結(jié)果是cls地址诸狭,我們加入一個FJFPerson的實例對象tmpPerson,發(fā)現(xiàn)tmpPersonisaISA_MASK相與也是真正的類FJFPerson地址,即cls的地址君纫。

地址.png
(lldb) p/x cls
(id) $0 = 0x0000000104c98fe8
(lldb) p/x obj
(FJFPerson *) $1 = 0x000000016b16bd78
(lldb) p/x tmpPerson->isa
(Class) $2 = 0x000001a104c98fed FJFPerson
(lldb) p/x 0x000001a104c98fed & 0x0000000ffffffff8ULL
(unsigned long long) $3 = 0x0000000104c98fe8
(lldb) p/x 0x0000000104c98fe8 & 0x0000000ffffffff8ULL
(unsigned long long) $4 = 0x0000000104c98fe8

我們將FJFPerson類地址與ISA_MASK掩碼進行位數(shù)的比對:

0x0000000  1  0  2  f  1   4    f   e    8
0x0000000  f  f  f  f  f   f    f   f    8

我們會發(fā)現(xiàn)ISA_MASK掩碼為1的位數(shù)是大于類地址的位數(shù)驯遇,而后面的8即二進制的1000是因為字節(jié)對齊而補上的000,同時我們將其他幾個類地址打印輸出看一下:

其他類地址.png

這里我們可以推導(dǎo)出,類地址實例對象的isa指針ISA_MASK掩碼相與后得到的地址蓄髓,所以當(dāng)類地址再次和ISA_MASK掩碼相與之后得到的肯定是類地址本身叉庐。

因此,這道題目之所以能夠正常的調(diào)用会喝,就在于類地址的取值的設(shè)計陡叠,而上面說的如果某個地址指向類對象的地址玩郊,我們可以把這個地址當(dāng)做對象去用的說法,是有點牽強的枉阵,至少在arm64架構(gòu)上是這樣译红。

測試demo

三.補充

有簡友說這道題目的打印是個巧合,并建議我看一下release的相關(guān)匯編的堆棧兴溜。
這里我分別打印了 真機 iOS 13侦厚、iOS 12.2 、iOS9 release版本的匯編,模擬器 iPhone8 iOS13 release版本的匯編拙徽,模擬器 iPhone8 iOS11.2版本的匯編.

分析如下:

1. 真機 iOS 13 刨沦、 iOS 13、iOS 12.2 膘怕、iOS9 release版本的匯編(正常輸出)

匯編代碼:

FJFRuntimeInterviewQuestionDemo`-[ViewController viewDidLoad]:
    0x102b165e0 <+0>:   sub    sp, sp, #0x30             ; =0x30           將sp-0x30想诅,開辟棧空間
    0x102b165e4 <+4>:   stp    x29, x30, [sp, #0x20]                       將x29,x30放在(x29棧幀地址岛心、x30程序鏈接寄存器)(sp+0x20)的地址處
    0x102b165e8 <+8>:   add    x29, sp, #0x20            ; =0x20           將sp+0x20棧地址賦值給x29
->  0x102b165ec <+12>:  nop                                                空指令
    0x102b165f0 <+16>:  ldr    x8, #0x28e0               ; (void *)0x0000000102b18ee0: ViewController 將0x28e0的地址給x8
    0x102b165f4 <+20>:  stp    x0, x8, [sp, #0x10]        將x0, x8放入(sp+0x10)的地址處来破,x0是self(當(dāng)前viewController地址),x8是字符串(“ ViewController")
    0x102b165f8 <+24>:  nop                                               空指令
    0x102b165fc <+28>:  ldr    x1, #0x2824               ; "viewDidLoad”  將0x2824的值賦值給x1
    0x102b16600 <+32>:  add    x0, sp, #0x10             ; =0x10 將sp+0x10的值賦值給x0
    0x102b16604 <+36>:  bl     0x102b16990              ; symbol stub for: objc_msgSendSuper2 調(diào)用objc_msgSendSuper2
    0x102b16608 <+40>:  nop                                              空指令
    0x102b1660c <+44>:  ldr    x0, #0x288c               ; (void *)0x0000000102b18fa8: FJFPerson將0x288c的值賦值給ldr
    0x102b16610 <+48>:  nop                                              空指令
    0x102b16614 <+52>:  ldr    x1, #0x2814               ; "class”       將0x2814的值賦值給x1
    0x102b16618 <+56>:  bl     0x102b16984              ; symbol stub for: objc_msgSend 調(diào)用objc_msgSend
    0x102b1661c <+60>:  mov    x29, x29                                  將x29的值賦值給x29鹉梨,恢復(fù)棧
    0x102b16620 <+64>:  bl     0x102b169a8              ; symbol stub for: objc_retainAutoreleasedReturnValue 調(diào)用autorelase
    0x102b16624 <+68>:  str    x0, [sp, #0x8]                            將x0的值存儲到sp+0x8的位置  (void *)0x0000000102e80f80: FJFPerson即為cls
    0x102b16628 <+72>:  nop                                              空指令
    0x102b1662c <+76>:  ldr    x1, #0x2804               ; "print”       調(diào)用print
    0x102b16630 <+80>:  add    x0, sp, #0x8              ; =0x8 
    0x102b16634 <+84>:  bl     0x102b16984              ; symbol stub for: objc_msgSend
    0x102b16638 <+88>:  ldr    x0, [sp, #0x8]
    0x102b1663c <+92>:  bl     0x102b1699c              ; symbol stub for: objc_release
    0x102b16640 <+96>:  ldp    x29, x30, [sp, #0x20]
    0x102b16644 <+100>: add    sp, sp, #0x30             ; =0x30 
    0x102b16648 <+104>: ret   

堆棧信息:

iPhone真機堆棧

寄存器信息:

寄存器信息.png

2. 模擬器 iPhone8 iOS13 release版本的匯編(正常輸出)

FJFRuntimeInterviewQuestionDemo`-[ViewController viewDidLoad]:
    0x10dfde4cc <+0>:   pushq  %rbp                      rdp入棧
    0x10dfde4cd <+1>:   movq   %rsp, %rbp               將rsp的值賦值給rdp
    0x10dfde4d0 <+4>:   pushq  %r14                       r14入棧 
    0x10dfde4d2 <+6>:   pushq  %rbx                       rbx入棧 rbx為self的地址值
    0x10dfde4d3 <+7>:   subq   $0x20, %rsp                rsp - 0x20的值給rsp
    0x10dfde4d7 <+11>:  leaq   -0x28(%rbp), %rax          將rdp-0x28的地址給rax
    0x10dfde4db <+15>:  movq   %rdi, (%rax)                將rdi的值賦值給rax所在地址空間 rdi是self的地址值
    0x10dfde4de <+18>:  movq   0x29fb(%rip), %rcx        ; (void *)0x000000010dfe0ef8: ViewController 將字符串(viewController)賦值給rcx
    0x10dfde4e5 <+25>:  movq   %rcx, 0x8(%rax)            將rcx的值賦值給(rax+0x8),也就是字符串”viewController”賦值給rax+0x8所在地址
    0x10dfde4e9 <+29>:  movq   0x2940(%rip), %rsi        ; “viewDidLoad”讳癌,將字符串”viewDidLoad”的值賦值給rsi
    0x10dfde4f0 <+36>:  movq   %rax, %rdi                將rax的值賦值給rdi, rdi的值為rdp-0x28
    0x10dfde4f3 <+39>:  callq  0x10dfde85e              ; symbol stub for: objc_msgSendSuper2 調(diào)用objc_msgSendSuper2
->  0x10dfde4f8 <+44>:  movq   0x29a9(%rip), %rdi        ; (void *)0x000000010dfe0fc0: FJFPerson
    0x10dfde4ff <+51>:  movq   0x2932(%rip), %rsi        ; "class"
    0x10dfde506 <+58>:  movq   0x1afb(%rip), %r14        ; (void *)0x00007fff503b1780: objc_msgSend
    0x10dfde50d <+65>:  callq  *%r14                       調(diào)用objc_msgSend
    0x10dfde510 <+68>:  movq   %rax, %rdi                將rax的值賦值給rdi,rax即為cls
    0x10dfde513 <+71>:  callq  0x10dfde86a              ; symbol stub for: objc_retainAutoreleasedReturnValue 調(diào)用autorelease
    0x10dfde518 <+76>:  leaq   -0x18(%rbp), %rbx        將(rbp-0x18)的地址值給rbx
    0x10dfde51c <+80>:  movq   %rax, (%rbx)              將rax的值放入rbx所在的地址值,cls放在(rbp-0x18)
    0x10dfde51f <+83>:  movq   0x291a(%rip), %rsi        ; "print" 將”print“地址給rsi
    0x10dfde526 <+90>:  movq   %rbx, %rdi                將rbx的地址給rdi,即rdi的地址為(rbp-0x18)
    0x10dfde529 <+93>:  callq  *%r14
    0x10dfde52c <+96>:  movq   (%rbx), %rdi
    0x10dfde52f <+99>:  callq  *0x1adb(%rip)             ; (void *)0x00007fff503cb040: objc_release
    0x10dfde535 <+105>: addq   $0x20, %rsp
    0x10dfde539 <+109>: popq   %rbx
    0x10dfde53a <+110>: popq   %r14
    0x10dfde53c <+112>: popq   %rbp
    0x10dfde53d <+113>: retq  

堆棧信息:

堆棧信息.png

寄存器信息:

寄存器信息.png

3. 模擬器 iPhone8 iOS11.2版本的匯編 (崩潰)

匯編代碼

FJFRuntimeInterviewQuestionDemo`-[ViewController viewDidLoad]:
    0x104ce74cc <+0>:   pushq  %rbp                        rdp入棧
    0x104ce74cd <+1>:   movq   %rsp, %rbp                  將rsp的值賦值給rdp
    0x104ce74d0 <+4>:   pushq  %r14                        r14入棧  _UIApplicationLinkedOnVersion
    0x104ce74d2 <+6>:   pushq  %rbx                        rbx入棧     "count" 是char類型的字符串
    0x104ce74d3 <+7>:   subq   $0x20, %rsp                 rsp - 0x20的值給rsp
    0x104ce74d7 <+11>:  leaq   -0x28(%rbp), %rax           將rdp-0x28的地址給rax
    0x104ce74db <+15>:  movq   %rdi, (%rax)                將rdi的值賦值給rax所在地址空間
    0x104ce74de <+18>:  movq   0x29fb(%rip), %rcx        ; (void *)0x0000000104ce9ef8: ViewController 將字符串(viewController)賦值給rcx
    0x104ce74e5 <+25>:  movq   %rcx, 0x8(%rax)             將rcx的值賦值給rax+0x8地址
    0x104ce74e9 <+29>:  movq   0x2940(%rip), %rsi        ; “viewDidLoad" 將字符串”viewDidLoad”的值賦值給rsi
    0x104ce74f0 <+36>:  movq   %rax, %rdi                   將rax的值賦值給rdi
    0x104ce74f3 <+39>:  callq  0x104ce785e              ; symbol stub for: objc_msgSendSuper2 調(diào)用objc_msgSendSuper2
->  0x104ce74f8 <+44>:  movq   0x29a9(%rip), %rdi        ; (void *)0x0000000104ce9fc0: FJFPerson 將FJFPerson地址給rdi
    0x104ce74ff <+51>:  movq   0x2932(%rip), %rsi        ; “class" 將字符串”class“的地址值給rsi
    0x104ce7506 <+58>:  movq   0x1afb(%rip), %r14        ; (void *)0x000000010560b940: objc_msgSend 將objc_msgSend給r14
    0x104ce750d <+65>:  callq  *%r14                      調(diào)用objc_msgSend
    0x104ce7510 <+68>:  movq   %rax, %rdi                將rax給rdi存皂,rax為cls
    0x104ce7513 <+71>:  callq  0x104ce786a              ; symbol stub for: objc_retainAutoreleasedReturnValue 調(diào)用objc_retainAutoreleasedReturnValue
    0x104ce7518 <+76>:  leaq   -0x18(%rbp), %rbx        將(rbp-0x18)的值給rbx,
    0x104ce751c <+80>:  movq   %rax, (%rbx)             將rax的值放入rbx指向的地址空間
    0x104ce751f <+83>:  movq   0x291a(%rip), %rsi        ; “print” 將”print“地址給rsi
    0x104ce7526 <+90>:  movq   %rbx, %rdi                將rbx的值給rdi
    0x104ce7529 <+93>:  callq  *%r14                     調(diào)用objc_msgSend
    0x104ce752c <+96>:  movq   (%rbx), %rdi              
    0x104ce752f <+99>:  callq  *0x1adb(%rip)             ; (void *)0x0000000105608cc0: objc_release
    0x104ce7535 <+105>: addq   $0x20, %rsp
    0x104ce7539 <+109>: popq   %rbx
    0x104ce753a <+110>: popq   %r14
    0x104ce753c <+112>: popq   %rbp
    0x104ce753d <+113>: retq 

堆棧日志:

堆棧日志.png

寄存器信息:

寄存器信息.png

從以上測試結(jié)果晌坤,我們可以看出,是否崩潰取決于在cls之前入棧的值是否是NSObject類型旦袋,能否打印出my name is <ViewController: 0x7ff0aac05df0>,根本在于cls之前入棧的是否是self的地址骤菠。

因此之前的打印結(jié)果是ViewController對象的原因:
因為cls在棧上的數(shù)據(jù)結(jié)構(gòu)符合它作為真實類的數(shù)據(jù)結(jié)構(gòu),self.name的地址正好是self對象的地址,這個說法并沒有錯誤疤孕。

最后

如果大家有什么疑問或者意見向左的地方商乎,歡迎大家留言討論。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祭阀,一起剝皮案震驚了整個濱河市鹉戚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌专控,老刑警劉巖抹凳,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顷蟆,死亡現(xiàn)場離奇詭異渺氧,居然都是意外死亡,警方通過查閱死者的電腦和手機后控,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幸冻,“玉大人粹庞,你說我怎么就攤上這事∏⑺穑” “怎么了庞溜?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趁啸。 經(jīng)常有香客問我强缘,道長,這世上最難降的妖魔是什么不傅? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮赏胚,結(jié)果婚禮上访娶,老公的妹妹穿的比我還像新娘。我一直安慰自己觉阅,他們只是感情好崖疤,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著典勇,像睡著了一般劫哼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上割笙,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天权烧,我揣著相機與錄音,去河邊找鬼伤溉。 笑死般码,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乱顾。 我是一名探鬼主播板祝,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼走净!你這毒婦竟也來了券时?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤伏伯,失蹤者是張志新(化名)和其女友劉穎橘洞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舵鳞,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡震檩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抛虏。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡博其,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迂猴,到底是詐尸還是另有隱情慕淡,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布沸毁,位于F島的核電站峰髓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏息尺。R本人自食惡果不足惜携兵,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搂誉。 院中可真熱鬧徐紧,春花似錦、人聲如沸炭懊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侮腹。三九已至嘲碧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間父阻,已是汗流浹背愈涩。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留至非,地道東北人钠署。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像荒椭,于是被迫代替她去往敵國和親谐鼎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容