从源码分析atomic和nonatomic

atomic与nonatomic是iOS开发中最常用的属性修饰符。从名字上看一个是原子性操作,一个是非原子性操作。非原子性操作容易理解其实就是不保证线程安全。而原子性操作是要求保证线程安全的。今天从objc源码来分析atomic和nonatomic是如何实现的。

示例代码:

@interface XXObject : NSObject
@property (atomic, strong) NSString *name;
@property (nonatomic, strong) NSString *name;
@end

操作属性的方法被定义在objc-accessors.mm文件中。

setter

设置atomic属性时调用的是objc_setProperty_atomic方法,然后将方法转发到reallySetProperty中。方法源码如下:

void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
    // 偏移量为0,更改isa指针
    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];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }

    objc_release(oldValue);
}

从源码看逻辑非常容易理解,在进行值的设置时,根据对象地址从全局的哈希表中取出spinlock_t类型的锁。spinlock_t是一个C++类,内部使用的是os_unfair_lock锁来保证线程访问安全。os_unfair_lock是用来替代OSSpinLock的锁,它是一个自旋锁,解决了优先级反转问题。

nonatomic走的是不加锁逻辑。

getter

源码如下:

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    // 偏移量是0,返回当前对象的isa指针
    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();
    
    // 为了优化性能,在自旋锁的外部将对象放入自动释放池
    return objc_autoreleaseReturnValue(value);
}

对atomic属性进行访问时,调用的是objc_getProperty方法,内部也是通过自旋锁来解决多线程问题,出于性能优化考虑,苹果在自旋锁之外将对象放到自动释放池中。

nonatomic走的是不加锁逻辑。

总结

通过对源码的分析可以知道目前atomic的实现方式并不是通过@synchronized方式实现的,而是采用的更高性能的os_unfair_lock自旋锁来实现。

你可能感兴趣的:(从源码分析atomic和nonatomic)