老胡看OC之strong、copy、retain、nonatomic、atomic

一直在使用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、nonatomic、atomic)