美文网首页
老胡看OC之strong、copy、retain、nonatom

老胡看OC之strong、copy、retain、nonatom

作者: 老胡看OC | 来源:发表于2016-12-08 23:28 被阅读0次

    一直在使用property修饰符,从未深入研究过,今天抽时间去看看这些属性究竟在是什么意思,

    我们先来声明NSString对象,分别用strong、copy、retain 修饰。

    @property (nonatomic, strong) NSString *testa

    @property (nonatomic, retain) NSString *testb;

    @property (nonatomic, copy) NSString *testc;

    @property (atomic, copy) NSString *testd;

    @property (atomic, strong) NSString *teste;

    使用clang -rewrite-objc 命令,看到如下代码

    // testa getter

    static NSString * _I_ViewController_testa(ViewController * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_ViewController$_testa)); }

    // testa setter

    static void _I_ViewController_setTesta_(ViewController * self, SEL _cmd, NSString *testa) { (*(NSString **)((char *)self + OBJC_IVAR_$_ViewController$_testa)) = testa; }

    // testb getter

    static NSString * _I_ViewController_testb(ViewController * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_ViewController$_testb)); }

    // testb setter

    static void _I_ViewController_setTestb_(ViewController * self, SEL _cmd, NSString *testb) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct ViewController, _testb), (id)testb, 0, 0); }

    // testc getter

    static NSString * _I_ViewController_testc(ViewController * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_ViewController$_testc)); }

    // testc setter

    static void _I_ViewController_setTestc_(ViewController * self, SEL _cmd, NSString *testc) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct ViewController, _testc), (id)testc, 0, 1); }

    // testd getter

    static NSString * _I_ViewController_testd(ViewController * self, SEL _cmd) { typedef NSString * _TYPE;

    return (_TYPE)objc_getProperty(self, _cmd, __OFFSETOFIVAR__(struct ViewController, _testd), 1); }

    // testd setter

    static void _I_ViewController_setTestd_(ViewController * self, SEL _cmd, NSString *testd) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct ViewController, _testd), (id)testd, 1, 1); }

    // teste getter

    static NSString * _I_ViewController_teste(ViewController * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_ViewController$_teste)); }

    // teste setter

    static void _I_ViewController_setTeste_(ViewController * self, SEL _cmd, NSString *teste) { (*(NSString **)((char *)self + OBJC_IVAR_$_ViewController$_teste)) = teste; }

    getter

    在使用copy或者mutableCopy的时候将会调用objc_getProperty,其他的都一样

    id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {

    if (offset == 0) {

    return object_getClass(self);

    }

    // Retain release world

    id *slot = (id*) ((char*)self + offset);

    if (!atomic) return *slot;

    // Atomic retain release world

    spinlock_t& slotlock = PropertyLocks[slot];

    slotlock.lock();

    id value = objc_retain(*slot);

    slotlock.unlock();

    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.

    return objc_autoreleaseReturnValue(value);

    }

    setter

    strong和retain修饰的setter却不一样。

    1. strong是直接赋值的,这里的是交由ARC去维护retaincount,

    2. retain, copy是调用了objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct ViewController, _testb), (id)testb, 0, 0)

    3. strong 修饰下的nonatomic和atomic是一样的,

    我们再看看objc_setProperty如何实现的

    void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)

    {

    objc_setProperty_non_gc(self, _cmd, offset, newValue, atomic, shouldCopy);

    }

    objc_setProperty调用了objc_setProperty_non_gc,后面的两个参数看着比较面熟,一个是atomic对应的是nonatomic和atomic,shouldCopy对应的是copy或者是mutableCopy,2为mutableCopy、1为copy。这里有调用了reallySetProperty方法。

    void objc_setProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)

    {

    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);

    bool mutableCopy = (shouldCopy == MUTABLE_COPY);

    reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);

    }

    这里的更为熟悉了,atomic、copy、mutableCopy.

    static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)

    {

    if (offset == 0) {

    object_setClass(self, newValue);

    return;

    }

    id oldValue;

    id *slot = (id*) ((char*)self + offset);

    if (copy) {

    newValue = [newValue copyWithZone:nil];

    } else if (mutableCopy) {

    newValue = [newValue mutableCopyWithZone:nil];

    } else {

    if (*slot == newValue) return;

    newValue = objc_retain(newValue);

    }

    if (!atomic) {

    oldValue = *slot;

    *slot = newValue;

    } else {

    spinlock_t& slotlock = PropertyLocks[slot];

    oldValue = *slot;

    *slot = newValue;

    slotlock.unlock();

    }

    objc_release(oldValue);

    }

    atomic这里,我们看到了spinlock_t,这里就是实现了变量的原子属性。所以我们在使用atomic的时候,并不是线程安全的。

    相关文章

      网友评论

          本文标题:老胡看OC之strong、copy、retain、nonatom

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