1:assgin
简单的赋值 不更改索引计数 一般修饰的是基本的数据类型 如:NSIntger,CGFloat,int,float,double,char 这里要知道 基本的数据类型是分配在栈上的 栈的内存会由系统自己处理
//写法: @property (nonatomic,assign) float number; //setter方法: -(void)setNumber:(float)num{ number = num; }
注:assgin 也可以修饰对象;一般情况下不会使用,是因为被assgin 修饰的对象在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,从而引起也指针的问题。对象一般分配在堆上的某块内存,如果在后续的内存分配中,刚好分配到了这块地址,程序就会crash
2:copy
一般情况下,copy可以用于对不可变的属性修饰中,主要是NSArray /NSDictionary/NSString, 也可以用来修饰block。
//写法 @property (nonatomic, copy) NSString* name; @property (nonatomic, copy) void(^typeBlock)(BOOL selected); @property (nonatomic, copy) void(^cancelBlock)(); //setter方法 -(void)setName: (id)newName { if (name != newName) { [name release]; name = [newName copy]; } }
注:使用copy这个属性修饰符是浅拷贝,给新的对象B赋值该name属性后,B对象值更改后name属性的值不会改变。(如果使用strong修饰了name属性,B对象的值被修改了以后name的值也会变)
3:retain
retain修饰的对象,引用计数会+1,retain一般用来修饰非NSString 的NSObject类和其子类,retain只能修饰oc对象,不能修饰非oc对象,比如说CoreFoundation对象就是C语言框架,它没有引用计数,也不能用retain进行修饰
//定义 @property (nonatomic, retain) PopObject *popObject; //setter方法 -(void) setName: (id) nameStr { if (name != nameStr) { [name release]; name = [nameStr retain]; } }
注:两个对象A和B,如果A对象中引用B对象,并且用retain修饰;B对象中引用A对象,并且也用retain修饰。这个时候就是A和B相互引用,无法释放,造成内存泄漏。当泄漏严重时将会出现崩溃等问题。
解决办法:相互引用,一端用retain,一端用assign
4:strong
strong表示对对象的强引用,引用计数也会+1,用于可变的数组字典字符串,或者view控件等
两个对象之间相互强引用造成循环引用,内存泄漏。
//使用 @property (nonatomic, strong) NSArray *arr; @property (nonatomic, strong) NSMutableArray *mArray; @property (nonatomic, strong) UILabel *label; @property (nonatomic ,strong) NSString *str;
weak 表示对对象的弱引用,被weak修饰的对象随时可被系统销毁和回收,引用计数不会加1,比较常用的地方就是delegate属性的设置。
常见的修饰符问题:
assign和weak的区别:当它们指向的对象释放以后,weak会被自动设置为nil,而assign不会,所以会导致野指针的出现,可能会导致crash。
strong和weak的区别:
- strong :表明是一个强引用,相当于MRC下的retain,只要被strong引用的对象就不会被销毁,当所有的强引用消除时,对象的引用计数为0时,对象才会被销毁。
- weak : 表明是一个弱引用,相当于MRC下的assign,不会使对象的引用计数+1。
两个不同对象相互strong引用对象,会导致循环引用造成对象不能释放,造成内存泄漏。
6:nonatomic/atomic
系统默认的是atomic,为setter方法加锁,而nonatomic 不为setter方法加锁。
{lock} if (property != newValue) { [property release]; property = [newValue retain]; } {unlock}
为什么nonatomic要比atomic快。原因是:它直接访问内存中的地址,不关心其他线程是否在改变这个值,并且中间没有死锁保护,它只需直接从内存中访问到当前内存地址中能用到的数据即可(可以理解为getter方法一直可以返回数值,尽管这个数值在cpu中可能正在修改中)
@property int height; @synthesize height = _height; self.height = 0; for (i = 0; i < n; i++) { self.height ++; }
常见问题
1。block为什么使用copy?block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在ARC中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。