美文网首页
property的系统实现分析

property的系统实现分析

作者: 码农苍耳 | 来源:发表于2017-12-17 23:07 被阅读37次

    我们在使用@property这个快捷定义的时候,都没怎么注意系统是怎么实现的,那么我们来看看系统实现的,和我们自己写的setter方法是否一致呢?

    Strong

    我们来分析一下最简单的strong类型的实现。

    @property (nonatomic, strong) NSString *str;
    

    如果是我们自己写setter方法大概是:

    - (void)setStr:(NSString *)str {
      _str = str;
    }
    

    如果是MRC的话,可能是这样的:

    - (void)setStr:(NSString *)str {
      if (_str != str) {
        [_str release];
        _str = [str retain];
      }
    }
    

    当然系统的方法是经过优化的,直接调用的C方法,所以这里不再考虑MRC的写法,直接来对比ARC的结果。

    store strong

    首先我们来看下objc是如何实现strong的,根据objc的源码可以知道,强引用是通过一个objc_storeStrong的方法来实现的。其实现入下:

    void objc_storeStrong(id *location, id obj)
    {
        id prev = *location;
        if (obj == prev) {
            return;
        }
        objc_retain(obj);
        *location = obj;
        objc_release(prev);
    }
    

    这和我们上面MRC的写法类似,只不过是通过C方法来实现了retain和release。

    转换为C语言

    大家都知道objc的方法其实都是通过send message的方式转换为C语言调用的,所以一个基本的setter方法的最终结果应该是这样的:

    void setter(id self, SEL selector, NSString *str);
    
    具体实现

    根据反汇编结果,其中系统默认的实现汇编如下:

    sub    sp, sp, #0x30             ; 申请栈空间
    stp    x29, x30, [sp, #0x20]
    add    x29, sp, #0x20            
    adrp   x8, 17
    add    x8, x8, #0xfc0            
    stur   x0, [x29, #-0x8]
    str    x1, [sp, #0x10]
    str    x2, [sp, #0x8]
    ldr    x0, [sp, #0x8]
    ldur   x1, [x29, #-0x8]          ; x1 = self
    ldrsw  x8, [x8]                  ; 偏移量
    add    x8, x1, x8                ; x8 = self + 偏移量
    str    x0, [sp]                  
    mov    x0, x8                    ; x0 = x8
    ldr    x1, [sp]                  ; x1 = str
    bl     0x1000bcad8               ; objc_storeStrong(self + 偏移量, str)
    ldp    x29, x30, [sp, #0x20]
    add    sp, sp, #0x30             ; 退栈
    ret
    

    翻译为C语言大概就是这样的:

    void setStr(id self, SEL sel, NSString *str) {
        objc_storeStrong(self + delta, str);
    }
    

    而我们自定义的setter方法

    - (void)setStr:(NSString *)str {
      _str = str;
    }
    

    的反汇编结果却比系统的结果多出一些函数调用

    sub    sp, sp, #0x30             ; =0x30
    stp    x29, x30, [sp, #0x20]
    add    x29, sp, #0x20            ; =0x20
    add    x8, sp, #0x8              ; =0x8
    mov    x9, #0x0                  ; 
    stur   x0, [x29, #-0x8]
    str    x1, [sp, #0x10]
    str    x9, [sp, #0x8]
    mov    x0, x8
    mov    x1, x2
    bl     0x104d14ad8               ; symbol stub for: objc_storeStrong
    adrp   x8, 17
    add    x8, x8, #0xfc8            ; =0xfc8
    ldr    x9, [sp, #0x8]
    ldur   x0, [x29, #-0x8]
    ldrsw  x8, [x8]
    add    x8, x0, x8
    mov    x0, x8
    mov    x1, x9
    bl     0x104d14ad8               ; symbol stub for: objc_storeStrong
    mov    x8, #0x0
    add    x9, sp, #0x8              ; =0x8
    mov    x0, x9
    mov    x1, x8
    bl     0x104d14ad8               ; symbol stub for: objc_storeStrong
    ldp    x29, x30, [sp, #0x20]
    add    sp, sp, #0x30             ; =0x30
    ret
    

    翻译成C语言大概是这样的:

    void setStr(id self, SEL sel, NSString *str) {
        id tmp = nil;
        objc_storeStrong(&tmp, str);
        objc_storeStrong(self + delta, tmp);
        objc_storeString(&tmp, nil);
    }
    

    可以看到这里多出一个临时变量,而且即使编译优化为-os,也是同样的结果。这里不清楚为什么会产生一次临时变量,从结果上来看,是不如系统的默认行为的。

    Weak

    在objc的源码中,weak是通过objc_storeWeak来实现的,这个方法的实现比较复杂,涉及到了全局的弱引用表,这里就不作介绍了。

    同样,我们来对比下系统默认实现的weak类型,和我们重写的setter方法,从结果上来看也是产生了一个strong类型的临时变量。

    sub    sp, sp, #0x40             ; =0x40
    stp    x29, x30, [sp, #0x30]
    add    x29, sp, #0x30            ; =0x30
    adrp   x8, 17
    add    x8, x8, #0xfd0            ; =0xfd0
    stur   x0, [x29, #-0x8]
    stur   x1, [x29, #-0x10]
    str    x2, [sp, #0x18]
    ldr    x0, [sp, #0x18]
    ldur   x1, [x29, #-0x8]
    ldrsw  x8, [x8]
    add    x8, x1, x8
    str    x0, [sp, #0x10]
    mov    x0, x8
    ldr    x1, [sp, #0x10]
    bl     0x104f38ae4               ; symbol stub for: objc_storeWeak
    str    x0, [sp, #0x8]
    ldp    x29, x30, [sp, #0x30]
    add    sp, sp, #0x40             ; =0x40
    ret
    
    sub    sp, sp, #0x30             ; =0x30
    stp    x29, x30, [sp, #0x20]
    add    x29, sp, #0x20            ; =0x20
    add    x8, sp, #0x8              ; =0x8
    mov    x9, #0x0
    stur   x0, [x29, #-0x8]
    str    x1, [sp, #0x10]
    str    x9, [sp, #0x8]
    mov    x0, x8
    mov    x1, x2
    bl     0x1044d8ad8               ; symbol stub for: objc_storeStrong
    adrp   x8, 17
    add    x8, x8, #0xfc8            ; =0xfc8
    ldr    x9, [sp, #0x8]
    ldur   x0, [x29, #-0x8]
    ldrsw  x8, [x8]
    add    x8, x0, x8
    mov    x0, x8
    mov    x1, x9
    bl     0x1044d8ae4               ; symbol stub for: objc_storeWeak
    mov    x8, #0x0
    add    x9, sp, #0x8              ; =0x8
    str    x0, [sp]
    mov    x0, x9
    mov    x1, x8
    bl     0x1044d8ad8               ; symbol stub for: objc_storeStrong
    ldp    x29, x30, [sp, #0x20]
    add    sp, sp, #0x30             ; =0x30
    ret
    

    相关文章

      网友评论

          本文标题:property的系统实现分析

          本文链接:https://www.haomeiwen.com/subject/rdtpwxtx.html