@property属性关键字

@property 的属性关键字有 nonatomicatomicreadonlywriteonlyreadwriteassignretaincopystrongweakunsafe_unretainednonnullnullablenull_resettable

下面介绍一些常用的关键字:
1.) nonatomicatomic
不写的话默认就是 atomic ,默认关键字。atomicnonatomic 的区别在于,系统自动生成的 getter/setter 方法不一样。如果你自己写 getter/setter,那 atomic/nonatomic/retain/assign/copy 这些关键字只起提示作用,写不写都一样。

对于atomic的属性,系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。假设有一个atomic 的属性"name",如果线程 A 调[self setName:@"A"],线程 B 调[self setName:@"B"],线程 C 调[self name],那么所有这些不同线程上的操作都将依次顺序执行——也就是说,如果一个线程正在执行 getter/setter,其他线程就得等待。因此,属性 name 是读/写安全的。

但是,如果有另一个线程 D 同时在调[name release],那可能就会crash,因为 release 不受 getter/setter 操作的限制。也就是说,这个属性只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。

如果 name 属性是 nonatomic 的,那么上面例子里的所有线程 A、B、C、D 都可以同时执行,可能导致无法预料的结果。如果是 atomic 的,那么 A、B、C 会串行,而 D 还是并行的。

2.)readonly
只读属性,有getter方法,但是直接调用setter方法会报错。
但是我们还是可以利用KVCreadonly属性赋值。

例如:定义一个ACLStudent的类,该类里面有一个firstName属性。

屏幕快照 2018-05-05 下午12.14.23.png

如果直接调用setter方法,会报错
3D8A9C23-8DE2-4AC7-AD09-AFCB33EB66A3.png

改用KVC来赋值,就可以修改成功


FF4A8CEC-7A33-4294-A544-7BFED67945E0.png

或者
3A335D7F-2B13-4119-8E7E-C113E6E9B4F6.png

当使用 setValue:forKey: 来设置对象的属性时,会以下面的优先顺序来寻找对应的 key

  1. 消息接收对象会查找是否存在满足 set: 格式的存取方法。
  2. 如果不存在满足条件的存取方法,且消息接收对象的类方法 + (BOOL)accessInstanceVariablesDirectly返回 YES,那么该对象会以 _, _is, , is 的顺序查找是否存在对应的key。
  3. 如果存在对应的存取方法或者找到对应的实例变量,那么就会改变该 key 所对应的值 value。必要的话,value 所对应的值会从对象中解析出来,如 Representing Non-Object Values 所描述的那样。
  4. 如果没有找到对应的存取方法或者实例变量,那么该消息对象的 setValue:forUndefinedKey: 将会调用。

对于上述第2点说明一下,如果我们不想让 setValue:forKey: 方法改变对象的属性值,那么重写其类方法 + (BOOL)accessInstanceVariablesDirectly返回 NO (该方法默认返回 YES,即在不存在满足条件的存取方法时,允许直接访问属性对应的实例变量);在搜索实例变量时,会首先检查带下划线的实例变量,然后检查不带下划线的实例变量。

对于上述第3点举例说明,如果要修改对象的属性 NSInteger studentId, 注意其是 NSInteger 类型,我们在调用 setValue:forKey: 方法时可以像这样

[self setValue:@(20) forKey:NSStringFromSelector(@selector(studentId))];

传入一个 NSNumber 对象也可以,Objective-C 会处理好一切。

对于上面的示例,使用 setValue:forKey: 实际修改的是 _firstName 实例变量的值。不要忘记,我们在声明一个 firstName 的属性时,编译器会为我们自动合成一个_firstName 的实例变量。

总结:

当我们声明一个 readonly 的属性,外部可能会通过 KVC 修改该属性值。
为了避免 KVC 修改属性值,须将定义属性所在类的类方法 + (BOOL)accessInstanceVariablesDirectly重写,使其返回 NO.

3.)strongweak
strong : 持有对象,引用计数+1;
weak : 不持有对象,引用计数不变,只适用于对象。比如代理(为了防止循环引用),UI控件(add到父视图上时,被父视图持有。对UI控件的引用,iOS会自动将其设置为弱变量(weak))

不同的是, 当一个对象不再有strong类型的指针指向它的时候 它会被释放 ,即使还有weak型指针指向它。

一旦最后一个strong型指针离去 ,这个对象将被释放,所有剩余的weak型指针都将被清除。

weak修饰的对象被别的变量释放,那么弱变量会被自动设置为nil,这样可以有效地防止崩溃

4.) retainassignunsafe_unretained
assign : 修饰基础数据类型和C数据类型,当被释放后,变量不会被自动置为nil,会变成野指针。
unsafe_unretained :unsafe_unretained从命名就可以看出意义所在,unsafe即是不会自动设置为nil,如果对象被释放了,再进行访问,程序会crash;unretainedweak类似,不会影响对象的引用计数
retain :释放旧对象,创建新对象。 引用计数会+1,强引用。
copy : 拷贝一个新的对象,新对象的引用计数+1,释放旧对象。

5.) copy
首先我们看一下对象和指针,看图

@property属性关键字_第1张图片
指针和对象

中间这个 “=” 符号 将2段代码连在一起, 充当一个桥梁作用:

第一: 允许 p 指针 指向这个对象占用的内存区域的首地址(可以简洁的理解为 允许p指针指向对象)

第二: 将这个对象地址赋值给p指针

第三:后续所有对 “对象“的操作,都可以通过对p指针进行间接操作来完成。

copymutableCopy
copy 就是浅拷贝,mutableCopy就是深拷贝吗?
任何对象都可以执行 copymutableCopy

看一下官方关于深拷贝和浅拷贝的解释图:


@property属性关键字_第2张图片
浅拷贝和深拷贝

结论:
1.浅复制,复制的是指向对象的指针,并不会复制对象本身,不会创建一个新的对象;
2.,深复制,复制的是对象本身,会创建一个新的对象。

对引用计数的影响:
浅copy,类似strong,持有原始对象的指针,会使retainCount加一。浅copy和strong引用的区别仅仅是浅copy多执行一步copyWithZone:方法。

深copy,会创建一个新的对象,不会对原始对象的retainCount变化。

使用原则:

\ copy mutableCopy
不可变对象 原来的对象,不可变 新对象 ,可变
可变对象 新对象,不可变 新对象,可变

1.针对不可变对象调用copy返回该对象本身,调用mutableCopy返回一个可变对象(新的);

2.针对可变对象调用copy返回一个不可变对象(新的),调用mutableCopy返回另外一个可变对象(新的)。

3.针对集合类对象(NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSSet等)进行深拷贝,拷贝的是对象本身,变成一个新的对象,但是集合里面的元素,进行的是浅拷贝,拷贝的是地址。

注意:
使用copy,需要该对象遵循NSCopying协议;
使用mutableCopy,需要该对象遵循NSMutableCopying协议,否则会crash在copyWithZonemutableCopyWithZone 方法上。

例:
UIView及其父类 并没有像 数组 字典 字符串这些类一样 遵守 NSCopying, NSMutableCopying 协议,下面代码程序会crash。


.h里面
.m里面
崩溃日志
@property(nonatomic, copy)NSMutableArray *myCopyArray;

 self.myCopyArray = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
 [self.myCopyArray removeObjectAtIndex:0];

运行后crash:
 -[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x14fc18f20

所以使用的时候,要注意对象是可变的还是不可变的。

关于 copy 和 block

Block为什么使用copy修饰

参考:
链接:https://www.jianshu.com/p/b90a7c57c34e

你可能感兴趣的:(@property属性关键字)