本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢 !
atom: 原子,不可再分割的单位
atomic: 原子操作
nonatomic: 非原子操作
关于atomic
-
给属性加上atomic修饰,可以保证属性的setter和getter都是原子性操作,即可以保证setter和getter内部是线程同步(加锁、解锁 -- PropertyLock)的。
-
它并不能保证使用属性的过程是线程安全的。比如多条线程同时访问这个属性就不能保证线程安全
-
ios 开发中不推荐使用,因为频繁的加锁解锁太消耗性能;mac开发中使用较多。
-
注意: 是
内部
线程同步,不能够保证外部的线程同步,就是说无法保证外部访问的线程同步;
为什么使用nonatomic
- 使用起来对性能的消耗很低
- 在开发中很少会出现多条线程同时访问同一个属性的情况,即使会遇到也可以通过对访问过程加锁的方式解决,没必要对属性内部加锁。
objc-accessors.m源码
//加锁方案 os_unfair_lock
using spinlock_t = mutex_tt<LOCKDEBUG>;
template <bool Debug>
class mutex_tt : nocopy_t {
os_unfair_lock mLock;
public:
void lock() {
lockdebug_mutex_lock(this);
os_unfair_lock_lock_with_options_inline
(&mLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
}
void unlock() {
lockdebug_mutex_unlock(this);
os_unfair_lock_unlock_inline(&mLock);
}
};
散列表
StripedMap<spinlock_t> PropertyLocks;
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;
//slot: 属性内存地址
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) {//是nonatomic属性
oldValue = *slot;
*slot = newValue;
} else {//是atomic属性,就对赋值过程进行加锁
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock(); //加锁
oldValue = *slot;
*slot = newValue;
slotlock.unlock();//解锁
}
objc_release(oldValue);
}
//设置属性值
void objc_setProperty(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);
}
//获取属性值
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; //是nonatomic属性,直接返回属性地址
// Atomic retain release world 是atomic属性,就对取值过程进行加锁
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);
}
网友评论