美文网首页
Property中各修饰关键字源码剖析

Property中各修饰关键字源码剖析

作者: 如风如花不如你 | 来源:发表于2019-02-20 17:55 被阅读1次

在Property中有很多关键词来修饰属性:
strong weak retain copy assign unsafe_unretained
那么光会有不行,还得知道为什么吧?

strong

话不多,上来就干一个试试,我们就拿strong 先开刀.
NSObject.mm 文件中(objc->Source),有这样一段代码

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

如果我所料不差,应该就是strong的底层实现了,那么这段代码应该比较容易理解的了.
首先看方法结构分为两个参数, id *locationid obj,一个应该是当前对象所在地址,而另一个新指向的对象,随后进行比较,判断两者是否是引用相同的对象.

 if (obj == prev) {
        return;
    }

如果不相同,那么利用 objc_retain()函数进行引用计数+1,并且*location = obj;将新引用的对象赋值给当前的属性,最后利用objc_release()将原本引用的对象释放掉.
简单明了一气呵成,而且我们一般在MRC情况下给成员变量创建set方法的时候貌似也是这样干的.所以啊还是多看,多练呢.

copy

copy的实现过程在objc->Source->objc-accessors.mm
copy的实现过程并不是单一的函数就能解决的,需要多个函数进行操作,我们首先先看看其中牵涉到copy的:

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];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }

    objc_release(oldValue);
}

咋一看,差点怀疑人生,仔细一看,不过如此嘛.我们来分析一下.
从函数名称分析,嗯,很清晰,看来这是真正的Property Set函数底层了.
我们找到跟copy相关的

if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    }

嗯,代码简单明了,就是我们写copy和mutableCopy时的判断嘛,利用对应的copyWithZonemutableCopyWithZone分别实现浅拷贝和深拷贝嘛(内心一阵激动,这么简单,看来我们都离大神不远了.)

到这里copy基本就结束了,然而事情总不会一帆风顺.
于是往下看的时候又发现了一段相关的代码:

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);
}

嗯,这个函数名字看来是Property的Set函数了,跟前面对比看来有点伪.
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
这段代码也很简单,字面就能看懂,copy不能是MUTABLE_COPY,并且确定是个COPY.(想想开发这个的人员还蛮可爱的.),
bool mutableCopy = (shouldCopy == MUTABLE_COPY)mutableCopy也同理判断它是个MUTABLE_COPY.

然而到了这里也差不多了,我们幻想的底层实现也差不多就这样了,于是手一抖,往下又翻了一下,发现了另一段相关的代码:

// This entry point was designed wrong.  When used as a getter, src needs to be locked so that
// if simultaneously used for a setter then there would be contention on src.
// So we need two locks - one of which will be contended.
void objc_copyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong __unused) {
    spinlock_t *srcLock = nil;
    spinlock_t *dstLock = nil;
    if (atomic) {
        srcLock = &StructLocks[src];
        dstLock = &StructLocks[dest];
        spinlock_t::lockTwo(srcLock, dstLock);
    }

    memmove(dest, src, size);

    if (atomic) {
        spinlock_t::unlockTwo(srcLock, dstLock);
    }
}

void objc_copyCppObjectAtomic(void *dest, const void *src, void (*copyHelper) (void *dest, const void *source)) {
    spinlock_t *srcLock = &CppObjectLocks[src];
    spinlock_t *dstLock = &CppObjectLocks[dest];
    spinlock_t::lockTwo(srcLock, dstLock);

    // let C++ code perform the actual copy.
    copyHelper(dest, src);
    
    spinlock_t::unlockTwo(srcLock, dstLock);
}

嗯,事情果然没有那么简单.不过方法上面的注释也解释了,这个接口设计出现了问题,对此方法进行了安全性的考虑.

上图方法中出现的函数解释:

void *memmove(void *dest, const void *source, size_t count):
memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。

struct spinlock_t:自旋锁
用来避免竞争条件的一种机制,例如:当一个临界区的数据在多个函数之间被调用时,为了保护数据不被破坏,可以采用spinlock来保护临界区的数据

相关文章

  • Property中各修饰关键字源码剖析

    在Property中有很多关键词来修饰属性:strong weak retain copy assign unsa...

  • 临时仓库

    @property中有哪些属性关键字?/ @property 后面可以有哪些修饰符? nonatomic atom...

  • iOS中的修饰关键字

    1. iOS中定义属性、变量的修饰关键字 在声明@property 属性、变量时,总是要在括号中写上assign、...

  • iOS基础深入补完计划--Block相关原理探究

    前文地址:《iOS基础深入补完计划》 在前文、我们提到了property中的关键字copy可以修饰block。 那...

  • iOS 属性修饰词

    一、 property有哪些属性修饰词? 写在后面:Q:ARC下property的默认关键字是?A:@proper...

  • 18.@property中有哪些属性关键字?/ @propert

    @property中有哪些属性关键字?/ @property 后面可以有哪些修饰符? 属性可以拥有的特质分为四类:...

  • OC基础知识

    @property 修饰符什么情况使用 weak 关键字,相比 assign 有什么不同?怎么用 copy 关键字...

  • OC - property

    @property变量 1.@property定义的变量,默认的修饰符是什么? 关于ARC下,不显示指定属性关键字...

  • 面试题

    1.@property 后面可以有哪些修饰符?/@property中有哪些属性关键字?属性可以拥有的特质分为四类:...

  • 2018-04-27 iOS 百度一面面试题

    property 修饰属性的几个常用的关键字及含义, assgin、weak、copy、 strong,assgi...

网友评论

      本文标题:Property中各修饰关键字源码剖析

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