iOS—属性关键字

@property/@synthesize/@dynamic

  • @property
    我们经常会看到 属性 = getter + setter +成员变量
    但实际上@property会生成setter、getter的方法声明
  • @synthesize会在编译期创造一个指定的成员变量,并且生成属性的getter、setter的实现部分
  • 在以前,@property 要和 @synthesize 搭配使用
  • 后来,编译器引入了property autosynthesis,即属性自动合成。编译器会自动给 @property 添加 @synthesize。
    @synthesize propertyName = _propertyName;
    这行代码会在编译期间创造一个带下划线的实例变量名,同时使用这个属性生成getter 和 setter 方法。所以现在,我们的代码中已经很少看到 @synthesize 了。
  • 所以看起来 就相当于 属性 = getter + setter +成员变量
  • 但我们也可以使用@synthesize来指定属性对应的实例变量名,最好还是不要这样做,要遵守代码规范
  • 上述编译器会自动编写这些属性所需的方法,这一过程叫做“自动合成”,与之对应的就是“动态合成”
  • “动态合成”,即需要开发者自己来添加属性的实例变量名,实现getter、setter方法,这时就需要用到@dynamic
    在这里插入图片描述
    在这里插入图片描述
    很明显,使用@dynamic注意还要手动添加成员变量_str

系统默认关键字

  • 基本数据:atomic,readweite,assign
  • OC对象:atomic, readwrite,strong

属性的各种特质设定会影响编译器所生成的存取方法

原子性

原子操作,可以理解为不可被中断的一个或一系列操作

  • atomic,系统自动生成的setter、getter方法会进行加锁操作,仅保证属性读写安全,且耗性能
  • nonatomic,系统自动生成的setter、getter方法不会进行加锁操作

atomic是默认的属性关键字,atomic只是对属性的setter、getter进行加锁,当前线程正在读/写这个属性,其他线程必须在当前线程执行完才能对其进行读/写,atomic仅保证了属性的setter/getter的线程安全,并不能保证使用属性的过程是线程安全的

举例:
如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic并不能保证对象的线程安全。

在实际的iOS开发中,我们经常会对属性进行取值赋值,如果属性关键字是atomic,那就会有大量的加锁解锁,非常耗性能,而实际上,很少会出现多线程调用一个setter、getter,所以一般我们使用的是nonatomic。对于线程安全,我们需要自己在恰当的位置进行加锁解锁来保证。

读写权限

  • readwrite:其修饰的属性拥有“获取方法”(getter)和"设置方法"(setter)
  • readonly:其修饰的属性仅拥有"获取方法"(getter),不会生成setter方法

readwrite是默认属性
对readonly修饰的属性进行写操作会报错,但可以直接访问成员变量
在这里插入图片描述

引用计数

assign

assign是默认关键字,用来修饰基本数据类型
assign修饰对象类型,不会改变对象的引用计数
assign的对象会产生悬垂指针,当对象没有持有者被废弃时,assign修饰的对象指针还是会指向原来的地址,会产生悬垂指针。访问悬垂指针,可能会导致程序crash

unsafe_unretained

此特质的语义与assign相同,但它适用于“对象类型”,该特质表达了一种“非持有关系”(不保留,unretained),当目标对象遭到摧毁时,属性值不会自动清空,这一点与weak有区别。

weak

弱引用,表示该属性是一种“非拥有关系”。为这种属性设置新值时既不会保留新值也不会释放旧值,类似于assgin。 然而在对象被摧毁时,属性也会被清空(置nil)

__weak对性能会有一定的消耗,使用__weak,需要检查对象是否被释放,在追踪是否被释放的时候当然需要追踪一些信息,那么此时__unsafe_unretained比__weak快,而且一个对象有大量的__weak引用对象的时候,当对象被废弃,那么此时就要遍历weak表,把表里所有的指针置空,消耗cpu资源。

strong

strong 是对象的默认属性关键字,此特质表明该属性定义了一种“持有关系”,为这种属性设置新值时,设置方法既会先保留(retain)新值,并释放(release)旧值,然后再将新值设置上去

copy

此特质所表达的所属关系与strong类似,然后设置方法并不保留(retain)新值,而是将其复制(copy)

copy修饰不可变对象,strong修饰可变对象

  • copy修饰不可变对象、原对象为不可变对象时,将原对象赋值给属性,会将原对象进行copy,此时是浅复制,两个指针指向的是同一个地址。
  • copy修饰不可变对象,原对象为可变对象时,将原对象赋值给属性,会将原对象进行copy,此时是深复制,两个对象指向的不同的地址,属性所指的是可变对象的副本,原对象如果被修改的话,不会影响属性的值
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • copy修饰可变对象,如果原对象是不可变对象并赋值给属性,那么进行的是浅复制,指向同一地址
  • copy修饰可变对象,如果原对象是可变对象并赋值给属性,此时进行的是深复制,属性指向的是原对象的不可变副本,即此时属性为不可变对象,这时对属性进行增删改的操作,就会因为找不到方法而报错。

如果不可变对象用strong修饰的话,又会有什么结果呢
由于strong修饰属性在设置新值时,在setter方法中保留新值、并释放旧值,将新值设置上去,此时与原对象指向的是同一地址。
当原对象为可变对象时,将原对象赋给strong修饰的不可变对象,修改原对象,那我们不可变的对象也会随之改变
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • retain
    retain在ARC环境下使用较少,在MRC下使用效果与strong一致

一些问题

  • strong和weak的区别
    strong修饰的属性表示对对象的强引用,所指向的对象引用计数+1。
    weak修饰的属性表示对对象的弱引用,所指向的对象的引用计数不会增加,当所指的对象销毁时,weak修饰的属性会置nil
  • assign和weak的区别
    assign修饰基本数据类型,也能修饰对象。修饰对象类型时并不会改变对象的引用计数,当所修饰的对象被废弃时,对象指针还指向原来的地址,会产生悬垂指针,再次访问程序可能会crash
    weak只修饰对象类型,不能修饰基本数据类型。修饰对象类型时不会改变对象的引用计数,当所修饰的对象被废弃时,对象指针会自动置nil。此时访问对象指针或像对象指针发送消息并不会引起程序崩溃
  • unsafe_unretained和weak的区别
    unsafe_unretained和assign差不多,修饰对象类型不会改变对象的引用计数,对象被废弃时,对象指针仍指的是原地址,产生悬垂指针,再次访问可能会出错。
    weak修饰对象类型,不改变对象的引用计数,对象被销毁时,被weak修饰的对象指针会置nil。
    __weak对性能有一定的消耗,使用__weak,需要检查对象是否被释放,在追踪是否被释放的时候肯定会追踪一些信息,此时unsafe_unretained比weak快,而当一个对象有大量的weak引用对象时,当对象被废弃时,那么此时就要遍历weak表,将表里的指针都置nil,消耗cpu资源。
    当我们很明确对象的生命周期时,可以使用unsafe_unretained代替weak,可以稍微提高一点性能,但其实这点性能确实微乎其微
  • MRC下重写retain修饰变量的setter方法
    在这里插入图片描述
  • 深复制、浅复制
    深复制是内容复制,产生新对象,会产生新的内存空间
    浅复制是指针复制,没有产生新对象,会增加引用计数
  • NSMutableArray用copy修饰会出现什么问题
    无论原对象是可变类型还是不可变类型,赋值给copy修饰的NSMutableArray对象都会先进行copy,随后将一份不可变对象赋值给NSMutableArray对象,此时如果对NSMutableArray进行增、删、改就会因找不到方法导致程序崩溃
  • strong和copy关键字
    strong修饰可变对象类型。strong属性关键字会在setter方法中(先判断对象是否与参数相同)对新值进行retain,对旧值release,再将新值赋给对象指针。(ARC下retain,strong基本相同)
    copy修饰不可变对象类型,保证不可变对象类型指针指向的一定是不可变对象。copy属性关键字会在setter方法中(先判断对象是否与参数相同),对旧值release,将新值copy后赋给属性,MRC下copy实现如下
    在这里插入图片描述
  • 记录一下自己的愚蠢
    ARC下对象类型定义成成员变量,肯定也是默认带有__strong的
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • weak修饰的对象类型,如何实现当对象被销毁时,对象类型指针置nil
    。。。。
    后续补充
  • 协议、分类
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值