iOS:属性关键字

随笔8个月前发布 地平线无际
75 0 0

1、读写权限
readwrite(默认) :同时产生setter/getter方法
readonly:只有getter方法,没有sette方法

2、原子性
atomic(默认)、nonatomic
原子性 是保证赋值获取的线程安全,添加/移除不保证其线程安全。

3、引用计数
retain /strong:(ARC默认strong)
weak:ARC下使用,仅修饰对象类型,不增加修饰对象的引用计数,当所修饰对象被释放后,会自动置为nil,不会产生悬垂指针。
assgin:既可以修饰基本数据类型,也可以修饰对象类型。setter方法的实现是直接赋。修饰对象类型时,不改变对象的引用计数,会产生悬垂指针(当修饰的对象被释放后,assgin仍指向原对象指针,导致悬垂指针,这时候继续通过该指针访问元对象的话,就可能导致程序崩溃)
unsafe-unretained(mrc):与weak类似,但是在销毁时不能自动销毁,容易形成野指针。
copy:与strong类似,设置方法会拷贝一份副本。一般用于修饰字符串和集合类的不可变量,block也用copy修饰。

4、其他关键字
__weak:ARC情况下使用,弱引用对象,一般是在block内部使用__weak 重定义捕获到的self(或其他),避免循环引用,
__strong:ARC情况下使用,强引用对象,一般与__weak一起使用,防止在block里面用__weak修饰的对象过早被释放;
__block:允许block改变外部传进的变量值(具体原因查看 block知识小结)

@synthesize:可对属性的成员变量进行重命名
@dynamic:告诉编译器,属性的setter方法和getter方法由用户自己实现,不自动生成,若是用户没有自己实现,那么在运行到该属性的点语法时会由于找不到setter和getter方法而导致崩溃。

引用计数管理

MRC是手动管理引用计数。
ARC是LLVM(编译器)和runtime协作实现自动引用计数。

引用计数表,是哈希表。
通过对象地址找到对象的引用计数。

iOS:属性关键字

第0位:weakly_refrenced,当前对象是否有弱引用指针
第1位:deallocating,当前对象是否进行dealloc操作
第2-63位:RC,引用计数值,计算值时需要向右偏移两位,计算出的才是正确的值。

部分方法源码分析:

alloc 经过一系列调用最终调用c函数的calloc方法,实际上此时的没有设置引用计数+1,
但是读取的retainCount 为1,是因为读取retainCount方法中,设置了1的局部变量。

retain
1、根据当前指针,在sideTables中哈希查找获取当前对象的sideTable
2、在sideTable中哈希查找获取当前对象的引用计数值
3、引用计数+1,实际是偏移量+1操作

objc_object::sidetable_retain(bool locked)
{
#if SUPPORT_NONPOINTER_ISA
    ASSERT(!isa().nonpointer);
#endif
    SideTable& table = SideTables()[this];
    if (!locked) table.lock();
    size_t& refcntStorage = table.refcnts[this];
    if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
        refcntStorage += SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    return (id)this;
}

retainCount
1、根据当前指针,在sideTables中哈希查找获取当前对象的sideTable
2、设置局部变量(所以alloc来的数据就是此值)
3、查询获得当前对象的引用计数表
4、查找结果做向右偏移的操作,再结合局部变量做加1操作
所以alloc出来的读取的it数据是0,因为局部变量是1,经过操作之后,获取到的retainCount为1

objc_object::sidetable_retainCount() const
{
    SideTable& table = SideTables()[this];
    size_t refcnt_result = 1;
    table.lock();
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it != table.refcnts.end()) {
        // this is valid for SIDE_TABLE_RC_PINNED too
        refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
    }
    table.unlock();
    return refcnt_result;
}

release
1、根据当前指针,在sideTables中哈希查找获取当前对象的sideTable
2、查询获得当前对象的引用计数表
3、引用计数表中对应值 减一
4、当引用计数为0时,触发dealloc操作

objc_object::sidetable_release(bool locked, bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
    ASSERT(!isa().nonpointer);
#endif
    SideTable& table = SideTables()[this];
    bool do_dealloc = false;
    if (!locked) table.lock();
    auto it = table.refcnts.try_emplace(this, SIDE_TABLE_DEALLOCATING);
    auto &refcnt = it.first->second;
    if (it.second) {
        do_dealloc = true;
    } else if (refcnt < SIDE_TABLE_DEALLOCATING) {
        // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
        do_dealloc = true;
        refcnt |= SIDE_TABLE_DEALLOCATING;
    } else if (! (refcnt & SIDE_TABLE_RC_PINNED)) {
        refcnt -= SIDE_TABLE_RC_ONE;
    }
    table.unlock();
    if (do_dealloc  &&  performDealloc) {
        this->performDealloc();
    }
    return do_dealloc;
}

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...