iOS中property属性的关键字(史上最详解)

来源:互联网 发布:linux清空文件内容 编辑:程序博客网 时间:2024/06/05 01:53

昨天立了flag,今天就来开始第一篇文章吧。
property的关键字是我们平常写代码随时都会用到的,只要声明一个属性,就会用到这些关键字,先从最简单的讲起吧。

一、如何使用

property的关键字分三类:
- 一类是表示原子性(也就是线程安全)的,有atomic和nonatomic,默认是atomic,acomic也就是线程安全,但是我们一般都用的nonatomic,因为atomic的线程安全开销太大,影响性能,即使需要保证线程安全,我们也可以通过自己的代码控制,而不用atomic。
- 一类是表示引用计数的,有assign(iOS5以前用unsafe_unretained),strong,weak,copy。
* assign:* assign用于非指针变量,一般用于基础类型和C数据类型,这些类型不是对象,统一由系统栈进行内存管理。
weak:对对象的弱引用,不增加对象的引用计数,也不持有对象,当对象消失后指针自动指向nil,所以这里也就防止了野指针的存在。
strong:对对象的强引用,会增加对象的引用计数,如果指向了一个空对象,会造成野指针,平常我们用得最多的应该也是strong了。
copy:建立一个引用计数为1的新对象,赋值时对传入值进行一份拷贝,所以使用copy关键字的时候,你将一个对象复制给该属性,该属性并不会持有那个对象,而是会创建一个新对象,并将那个对象的值拷贝给它。而使用copy关键字的对象必须要实现NSCopying协议。
unsafe_unretained:跟 weak 类似,声明一个弱引用,但是当引用计数为 0 时,变量不会自动设置为 nil,现在基本都用weak了。
- 一类是表示读写权限的,默认是readwrite(可读可写),还有就是readonly,当你希望暴露出来的属性不能被外界修改时就需要申明为readonly。

二、关键字与内存管理

这里重点讲一下与内存管理相关的这几个关键字。
直接上代码吧

@property (nonatomic,strong) NSString *strongStr;@property (nonatomic,weak) NSString *weakStr;

测试

self.strongStr = @"string";self.weakStr = self.strongStr;self.strongStr = nil;NSLog(@"strongStr=%@,weakStr=%@",self.strongStr,self.weakStr);

输出结果为
strongStr=(null),weakStr=string
有人可能会奇怪,为什么这里weakStr还是指向@”string”,strongStr都已经为为空了,weakStr也应该为空啊,weak关键字本来就不会使对象的引用计数加1。这里主要是因为NSString类型的赋值默认会加上copy,而copy会创建一个新的对象(后面再具体介绍)。也是就是说这里的赋值语句其实就是

self.strongStr = [@"string" copy];self.weakStr = [self.strongStr copy];

由于NSString类型的特殊性,所以后面我自己创建一个Person类继续进行试验。
同样的还是weak和strong

@property (nonatomic,strong) Person *strongPerson;@property (nonatomic,weak) Person *weakPerson;

试验代码一样

self.strongPerson = [Person new];self.weakPerson = self.strongPerson;self.strongPerson = nil; NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果为:
strongStr=(null),weakStr=(null)
这里就足以说明weak修饰的属性并不会使引用计数增加

稍微修改代码,把strongPerson设置为nil

self.strongPerson = [Person new];self.weakPerson = self.strongPerson;self.weakPerson = nil;NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果如下:
strongStr=<Person: 0x600000007d50>,weakStr=(null)
说明weak修饰的属性只是对对象的弱引用,并不会真正的持有该对象。
再次修改代码

    Person *p = [Person new];    self.strongPerson = p;    self.weakPerson = self.strongPerson;    p = nil;    NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果为:
strongStr=<Person: 0x600000200b50>,weakStr=<Person: 0x600000200b50>
这里不用多说,因为strong属性会强引用该对象并使该对象的引用计数+1,所以即使把p设置为nil,该对象也并没有释放,要想释放该对象,还得把strongStr设置为nil。
self.strongPerson = nil;
这样输出结果就是 strongStr=(null),weakStr=(null)了。

再来看看copy关键字
为了方便试验,给person加了一个name属性。
@property (nonatomic,copy) NSString *name;

    NSString *a = @"xiaoming";    Person *p = [Person new];    p.name = a;    NSLog(@"p.name=%@",p.name);

毫无疑问,输出结果为xiaoming。但是此时改一改a的值呢?

    NSString *a = @"xiaoming";    Person *p = [Person new];    p.name = a;    a = @"xiaohua";    NSLog(@"p.name=%@",p.name);

输出结果:p.name=xiaoming。如前所说,copy关键字修饰的属性是将对象拷贝一份赋值,所以你改变原对象并不会对拷贝后的对象有任何改变。

在这里要重点说一下,使用NSMutableArray,NSMutableDictionary等可变集合对象的时候千万不要用copy,这里用copy 99%会出错,因为当你给该属性赋值时它会自动调用对象的copy方法,从而将可变集合转换成不可变集合,把一个不可变集合赋值给一个可变集合,就会造成错误。

感觉写得有些啰嗦,我觉得主要是给新人看吧,毕竟我自己当初一直对这些关键字也是懵懵懂懂的,如果看了我这篇文章还是不能理解,那应该是完全不了解内存管理方面的知识,MRC、ARC应该去了解一下,如果后面有需要,我可能会写一篇相关的文章。

另外,还请大神门多多指教。。。。

0 0