@property参数
- 通过
property
声明的属性会自动生成setter/getter方法. nonatomic
<–>atomic
readwrite
<–>readonly
strong
/copy
/assign
synthesize
有些代码可能会使用@synthesize
关键字(iOS5之前).iOS5之后,property已经优化了该属性,自动生成setter/getter方法
1 | Person.h |
使用了`synthesize`关键字后,就是告诉编译器要自己生成两个方法,其中
@synthesize age = _age;
这句话的意思就是age
属性给_age
的成员变量生成setter/getter方法,在setter中实际操作的是_age
.
通过使用
synthesize
关键字,可以在赋值操作时候重新定义一个接受值的成员变量,使得命名更清晰.
atomic
/ nonatomic
atomic: 原子属性, 生成的setter和getter方法是一个原子操作。如果有多个线程同时调用setter的话,不会出现某一个线程执行setter全部语句之前,另一个线程开始执行setter的情况,相当于方法头尾加了锁一样。虽然安全性高,但是会导致程序特别的卡(开发中一般不用这个属性)
nonatomic : 非原子属性,多线程的情况下数据可能会有问题,但是会提高性能。
readwrite
/ readonly
readwrite:默认属性,系统会自动生成setter 和 getter方法的声明与实现.
readonly:只读属性,只会生成getter不会生成setter
assign
这个属性一般处理基本数据类型,比如int,char,float等,assign是默认的,可以不加这个属性。并且不会更改引用计数。
copy / strong
NSString赋值操作
无图无真相:
1 | @interface ViewController () |
首先声明了一个copy
和strong
类型的字符串.1
2
3
4
5
6NSString * originStr = @"9999";
self.copyedStr = originStr;
self.strongStr = originStr;
NSLog(@"originStr: %p . address : %p",originStr,&originStr);
NSLog(@"_copyedStr: %p . address : %p",_copyedStr,&_copyedStr);
NSLog(@"_strongStr: %p . address : %p",_strongStr,&_strongStr);
对copy
及strong
类型的属性进行赋值这里使用的是setter方法,而不是成员变量,输出结果:
1 | 2018-02-28 16:59:49.368224+0800 copystrong[60607:2244516] originStr: 0x10c8570a0 . address : 0x7ffee33a7af8 |
从上可以看出来,不管是copy
还是strong
都指向了同一个地址.
1 | (lldb) memory read 0x10c8570a0 |
由此可查看出来在指向地址的高一位时,地址上存储的值是对变量的值.
在此之后对原来的str进行重新赋值,看看有什么变化.
1 | originStr = @"newStr"; |
之后重新输出:
1 | 2018-02-28 17:04:48.902472+0800 copystrong[60607:2244516] originStr: 0x10c857120 . address : 0x7ffee33a7af8 |
此时originStr
的指针不变,但是指向的地址生变化,重新申请了一份内存.继续查看内存上的地址:
1 | (lldb) memory read 0x10c857120 |
同样的,在该地址的高一位找到了我们赋值的值.再看看通过copy
和strong
修改的值:
1 | 2018-02-28 17:08:00.954336+0800 copystrong[60607:2244516] _copyedStr: 0x10c8570a0 . address : 0x7fb15bf0da70 |
还是第一次赋值的地址,且内容也没有变化.
总结一下哈:
- 通过多次赋值操作,字符串地址的变化大致得出结论,还有待证明(如果有大佬指出问题所在,请斧正!!!)
- 针对使用
NSString
对copy
或strong
修饰的属性没有任何影响.
NSMutableString赋值操作
没代码还说个🐓
1 | NSMutableString *originStr = [NSMutableString stringWithFormat:@"heiguo"]; |
同样的操作,使用setter
方法进行赋值.结果如下:
1 | 2018-02-28 17:14:23.468627+0800 copystrong[60820:2254432] originStr: 0x60400044d290 . address : 0x7ffee67e6af0 |
在这里细看:
- originStr 和 strongStr 地址是一样的.
- copyStr 地址是一个很大的值(此时这个地址在堆上)
直接使用po
:
1 | (lldb) po 0xa006f75676965686 |
此刻及证明第二点.
同样的进行重新赋值操作:
1 | [originStr appendFormat:@"append"]; |
继续输出:
1 | 2018-02-28 17:17:48.128857+0800 copystrong[60820:2254432] originStr: 0x60400044d290 . address : 0x7ffee67e6af0 |
结合第一次输出:
- 在修改originStr 后,
strong
修饰的变量值跟着改变为新的地址(同新的originStr一致). - 即使修改originStr后,
copy
修饰的变量一样使用第一次赋值的值.
回归主题 –> copy
/ strong
借用网上众多深拷贝,浅拷贝之说:
- 深拷贝: 开辟一块新内存地址,使用指针指向这块地址.对原来的对象引用计数不变.
- 浅拷贝: 对原内容增加一个指针指向,可以理解成引用计数器+1.
- 在使用
copy
修饰时,深拷贝还是浅拷贝,这个和被copy的对象是什么类型有关:借大佬图
水平有限,内容若有不妥,请斧正!!!