@property
@property是在声明属性时快速创建getter、setter存取器,并通过一些修饰符来控制线程安全(atomic、nonatomic)、访问权限(readwrite、readonly)、ARC内存管理(assign、strong、weak、copy、unsafe_unretained)、MRC内存管理(assign、retain、copy)、指定存取方法名(setter = 、getter = )等。
注:@synthesize是在.m中,生成@property定义的属性的setter、getter的实现,如今都由系统默认实现getter、setter,无需手动添加@synthesize。
@property还默认生成了_obj的实例变量,self.obj实际上默认调用了set、get方法,而_obj是直接访问了实例变量。
@synthesize obj = _obj(别名,或者说是定向到属性的实例变量名,可以是任意名称),当在同时重写getter、setter方法的时候,系统不会添加_obj实例变量名,所以要手动添加别名用于setter和getter中。
atomic(默认)和nonatomic
atomic属于原子操作,当前存取器上线程安全,比较耗费系统资源,可防止多线程同时访问写入造成的数据错误。nonatomic相反。
readwrite(默认)和readonly
readonly只生成getter没有setter。为了属性值更便于理解可自定义存取访问器名称:
@property (nonatomic, setter = mySetter:, getter = myGetter) NSString *name;
assign(默认)
多用于非指针变量的基本数据类型(NSInteger)以及C数据类型和id。MRC模式中修饰delegate等指针变量。
注:在ARC模式中,用assign关键字修饰指针变量,对象被回收会造成野指针。
而在MRC模式中,因为没有weak的出现所以只能用assgin修饰delegate、IBOutlet这类特殊对象,手动将对象 = nil可避免野指针的情况。
strong(ARC)
强引用,指向同一块内存地址,引用计数+1。属于浅拷贝(指针拷贝)用于代替MRC中的retain关键字,但自行管理引用计数。
weak(ARC)
弱引用,对传入的对象不持有,即不增加传入对象的引用计数,所以传入对象释放时,weak声明的变量指向nil,为了避免野指针,也被置为nil。
多用于delegate、IBOutlet等声明,是避免野指针进阶版的assign。
self.model = [[Model alloc] init]; //self.model强引用Model
self.model.delegate = self; //model.delegate弱引用self
copy(ARC)
在声明非可变对象时,copy和strong在内容和内存管理上是没有区别的,都只做了浅拷贝,与传入对象指向同一块内存地址。
但对于可变对象(NSMutableString、NSMutableArray等),copy声明的对象做了一下深拷贝产生了新对象,并且由于底层是调用了[obj copy]方法,可变对象都转换成了不可变类型(NSMutableString→NSString)。
copy关键字主要是为了:避免对可变的源数据对象造成污染。
unsafe_unretained(ARC)
unsafe_unretained关键字事实上是iOS5以后的ARC时代为了向下兼容(因为iOS5以前没有weak属性)而存在的。但在我的理解中,它应该是等价于assign关键字。
retain(MRC)
等同于ARC时代的strong,都是增加引用计数的强引用对象,不能用来修饰基础数据类型。
MRC和ARC
MRC
MRC(Mannul Reference Counting)内存管理模式下,我们使用retain、release、autorelease等方法对变量进行手动内存管理。
Number *num = [[Number alloc] init]; //num指向了[[Number alloc] init]初始化后的内存,这块内存的引用计数为1
Number *num2 = [num retain]; //num2通过num指针retain又增加了这块内存的引用计数,现在为2
[num2 release]; //释放num2指针对内存的所有权,引用计数-1,现在为1
[num release]; //释放num指针对内存的所有权,引用计数-1,现在为0,和num2的释放顺序无关紧要,此时这块内存被释放,num和num2都变成野指针
注:引用计数是针对[[Number alloc] init]这块内存的,num、num2等都是指向这块内存的指针而已,每个指向这块内存的指针都会使这块内存的引用计数+1。
[num autorelease]; //放入自动释放池,稍后某个时刻(每个runloop执行完成后)释放。
@autoreleasepool
自动释放池,除直接release外的另一种管理内存释放的方式。
ARC时代,系统自行管理释放池,对象无法调用autorelease,但可使用autoreleasepool,每次事件循环(RunLoop)结束后(通俗的可理解为花括号的结束),autoreleasepool就会回收池中的内存。autoreleasepool排布在栈中,对象受到autorelease消息后,系统将其放入栈顶的池里,由系统自动释放。
需要手动创建autoreleasepool的情况:
1、main():main()函数的末尾是应用程序的终止,当你在main()中加入其它代码时,手写的这个autoreleasepool实际上是为默认的自动释放池无法容纳的对象,提供一个最外围的自动释放池。
2、当你的循环中创建了许多临时对象时,应加入autoreleasepool避免内存爆发式增长。
for(inti =0; i <10000; i++) {
NSString*str =@"test"; //不加autoreleasepool,对象在for循环结束前会不断创建,占用大量内存
@autoreleasepool{
NSString*str =@"test"; //手写的自动释放池会在单次循环结束后就回收临时对象
arr.add(str)
}
}
ARC
ARC(Automatic Reference Counting),自动引用计数,即在编译过程中自动加入了MRC模式下的retain、release。
与MRC模式混编:在文件的flags中添加-fno-objc-arc / -fobjc-arc,