一.写在前面的话
为什么要把他排在第一位?这是有原因的,因为这破玩意在开发中很少会引起注意,一般人都是一带而过,不去深究那些细节.
在这里我要给一直在开发路上奔波的新手们说一句公道话
这里东西,即使不去深究一般的开发也不会出现问题,因为一个小小的属性修饰符就否定一个人,我觉得这已经不是草率的问题了,而是你内心的狭隘.
好了接下来我们进入正题,属性修饰符嘛,顾名思义就是修饰属性的,而属性是什么呢?很简单,我就用我自己的理解,就是个全局变量,在程序每个地方都可以使用到,那么与成员变量的区别是什么呢?除了充当一个成员变量以外,就是自动生成了一个setter方法和一个getter方法,使程序员们方便使用了。
二.属性修饰符
属性修饰符都有哪些呢:
strong/retain
assign/weak
copy
atomic/noatomic
readwrite/readonly
strong/retain:
strong是ARC下新引入的属性修饰符但它在MRC下仍然可以使用,你可以把它当成MRC中的retain,用它修饰就是强引对象,retainCount会加1
假设有一个属性
@property (nonatomic, strong) NSString *name;
在ARC下,这时它的setter方法应该这样
- (void)setName:(NSString *)name {
_name = name;
}
而MRC下的retain的setter方法是这样
- (void)setName:(NSString *)name {
//如果地址不一样,证明_name与name是不同的值
if (_name != name) {
//这时我们先把旧值释放 防止内存泄露
[_name release];
//然后把新值强引用(retainCount+1)赋值于成员变量上
_name = [name retain];
}
}
assign/weak:
assign:
首先讲一下assign
这个东西是专门用来修饰基本数据类型,在iOS开发中什么是基本数据类型呢?通俗的讲就是非对象类型,比如int、float、double、NSInteger,这种数字类型就称为基本数据类型,他们都不是对象,但是万事没有那么绝对的,它也可以修饰对象,但是那么做是十分不安全的,那么为什么这个修饰符不能修饰对象呢?那是因为assign是弱引用,如果用它修饰对象,那么对象一旦创建就会立即被释放,然而assign依然会保留对象的指针,但是对象已经消失了,所以该指针指向了一块被释放的内存区域,即为野指针,当野指针调用对象方法的时候(向对象发送消息),就会发生崩溃。
weak:
weak与assign一样是弱引用,但是weak是用来修饰对象的,苹果规定不能用它修饰基本数据类型,如果修饰立即就会报错
上面说了weak也是弱引用,为什么苹果会允许它修饰对象呢,因为weak上面添加了一个安全机制,如果weak所引用的对象被释放了,就会把weak上的指针设置为nil,这样当对象再执行方法的时候,就不会发生崩溃了,因为即使对象被释放了,向nil发送消息也不会造成崩溃,所以使用weak修饰对象是安全的。
有些人可能不理解为什么要使用weak在这里我给你们抛一块砖
设想有这样一种情况,当一个子视图由于某种原因要将它的父控制器作为自己的属性,以便于在子视图的各个角落都可以调用调用到父控制器的方法,这时如果你使用strong来修饰这个父控制器就会出现子视图强引用父控制器导致父控制器无法被释放的问题,这就是所谓的内存泄漏,所以这里需要使用weak来修饰它的父控制器,由于weak是弱引用,不会让父控制器引用计数增加,这样就既不会造成内存泄漏,又可以优雅的使用父控制器对象了。
copy:
这个东西往浅了说就是复制, 往深了说需要说好几大篇章, 其实就是在对象进行setter方法时先对对象做复制操作, 而对可变变量和不可变变量的复制是不一样的, 这里总结一下, 对不可变变量的复制都是拷贝指针, 也就是常说的浅拷贝, 而对可变变量的copy会复制出一个一模一样的克隆人放在另一块内存地址中, 只不过该变量从此不可变, 说到这里可能有人对mutableCopy有疑问, 这个东西不是属性修饰符, 所以我就顺便告诉你一下, 就一句话
只有不可变对象进行copy才是浅拷贝, 其他都是深拷贝
下面写一下copy的setter方法
ARC下
- (void)setName:(NSString *)name {
_name = [name copy];
}
MRC下
- (void)setName:(NSString *)name {
//如果地址不一样,证明_name与name是不同的值
if (_name != name) {
//这时我们先把旧值释放
[_name release];
//然后把新值强引用(retainCount+1)赋值于成员变量
_name = [name copy];
}
}
atomic/noatomic
这两个东西我自己也不是特别清楚, 毕竟还是很年轻, 但是你记住atomic是原子性, 使用这个修饰符可以保证线程安全但是会降低效率, 而noatomic是非原子性, 不会保证线程安全, 但效率比atomic高, 我们开发中一般都是用noatomic.
readwrite/readonly:
先挑简单的说readwrite就是可读写,不加这个属性修饰符默认就是如此,所有变量都是可以读写的,也就是都自带setter和getter方法,而使用readonly修饰系统会自动生成getter方法而不生成setter方法所以是只读的,无法赋值。