美文网首页iOS学习征服iOSiOS 开发每天分享优质文章
iOS中property的关键字(史上最详解)

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

作者: Tamp_ | 来源:发表于2017-04-21 16:14 被阅读1251次

昨天立了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) 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修饰的属性并不会使引用计数增加

稍微修改代码,把weakPerson设置为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关键字
为了方便试验,我们直接在ViewController里面加个属性。
@property (nonatomic, copy) NSObject *c;

    NSObject *a = [[NSObject alloc]init];
    self.c = a;
    a = nil;
    NSLog(@"%@",self.c);

毫无疑问,输出结果不为nil。

    <NSObject: 0x600000010d90>

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

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

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

更新

之前是用NSString来做的实验,但是由于字符串的特殊性,所以有点容易误导大家,现在已经全部改成了普通类了。关于字符串类型,主要是苹果在编译期做了一些优化,让它的特性跟普通变量有点类似,在这里就不说太多了,以免给大家造成困惑。

相关文章

网友评论

  • Self_Time:retain自从引用计数被strong代替后,还有作用嘛
    Self_Time:@Tamp__ 嗯,创建block中的修饰属性retain=assign,strong = copy
    Tamp_:@我又不搞事 实际上retain和strong是可以相互替换的,只是推出strong后都用strong了。只是在部分类型中strong和retain表现有不同,比如NSString和block,这时候用strong等同于copy,猜测这应该是编译器做了一些事情
  • jadyn_JT:NSString *a = @"xiaoming";
    Person *p = [Person new];
    p.name = a;
    a = @"xiaohua";
    NSLog(@"p.name=%@",p.name);

    楼主,这里的p.name = a中p.name 和 a应该还是指向同一个对象,并不是去拷贝一个新的对象,应该是只拷贝了a的指针。
    a = @"xiaohua" 是a重新指向了一个新的对象,但并不会对p.name有影响,所以p.name的值才不会改变
    Tamp_:@jadyn_JT 谢谢纠正,这篇文章我需要更新一下了!
  • stephenhe:输出结果为
    strongStr=(null),weakStr=string
    有人可能会奇怪,为什么这里weakStr还是指向@"string",strongStr都已经为为空了,weakStr也应该为空啊,weak关键字本来就不会使对象的引用计数加1。这里主要是因为NSString类型的赋值默认会加上copy,而copy会创建一个新的对象(后面再具体介绍)。

    -- 请问这里确实会默认加吗?有点不确定
    stephenhe:试图修改这个string,weakStr是会变化的,似乎没有创建新对象。
    stephenhe:我看有个文章写 property的属性默认是:readwrite,assign, atomic;而且@"string"产生的是一个NSConstantString,是无法被释放的,所以weak指向的内容是还存在的。以上不知道是不是我误解。我再找找具体的说法。
    Tamp_:@stephenhe 确定会加啊,我这里例子不就展示出来了吗。你要不确信的话也可以自己试试的
  • 9a6ff6b40f74:干的漂亮 ,还不懂 怎么办
    Tamp_:你搞iOS多久了哦,建议你好好搞搞基础,像这些基础应该是入门必备的吧。主要是要理解它的工作原理。
    9a6ff6b40f74:@Mr不怎么right 我是啥也不理解 那个类对应那个属性 都会背了
    Tamp_:@Mr_Xing 哪里不懂呢?

本文标题:iOS中property的关键字(史上最详解)

本文链接:https://www.haomeiwen.com/subject/qcddzttx.html