iOS cop/assign /strong/weak
1、OC中字符串为什么要用Copy
在iOS开发中,我们在定义一个NSString的时候都会用copy来修饰,
@property (nonatomic, copy)NSString *str;
那为什么不用strong呢,我写了一个测试,来简单的说明一下
首先把修饰符写成strong
在viewDidLoad的方法中,定义一个可变的字符串
@property (nonatomic, strong)NSString *str;
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *string = [NSMutableString string];
[string appendString:@"hello"];
self.str = string;
NSLog(@"%@",self.str);
[string appendString:@"World"];
NSLog(@"%@",self.str);
}
输出的结果是
NSString中copy的问题[3807:239891] hello
NSString中copy的问题[3807:239891] helloWorld
我们只给self.str附了一次值,但是self.str 的值改变了,这是因为把可变字符的地址指向了str,所以string的值改变了,self.str也跟着改变,
我们把strong改成copy以后
@property (nonatomic, copy)NSString *str;
输出的结果
NSString中copy的问题[3852:242597] hello
NSString中copy的问题[3852:242597] hello
输出的结果显示,self.str的值只做了一次的修改,
这样就能保证了在代码中,数据的安全
2、iOS中weak和assign的区别
assign和weak的区别
大致的意思是说,weak比assign多了一个功能就是当属性所指向的对象消失的时候(也就是内存引用计数为0)会自动赋值为nil,这样再向weak修饰的属性发送消息就不会导致野指针操作crash。当assign指针所指向的内存被释放(释放并不等于抹除,只是引用计数为0),不会自动赋值nil,这样再引用self.assignPoint就会导致野指针操作,如果这个操作发生时内存还没有改变内容,依旧可以输出正确的结果,而如果发生时内存内容被改变了,就会crash。
本质区别
速度比较: __unsafe_unretained > __weak
@property (nonatomic, assign) Test *test; // 真实类型是 Test *__unsafe_unretained _test;
__unsafe_unretained的特点:
1.不是强引用, 不能保住OC对象的命
2.如果引用的OC对象销毁了, 指针并不会被自动清空, 依然指向销毁的对象(很容易产生野指针错误: EXC_BAD_ACCESS)
@property (nonatomic, weak) Test *test; // Test * _Nullable __weak test;
__weak的特点:
1.不是强引用, 不能保住OC对象的命
2.如果引用的OC对象销毁了, 指针会被自动清空(变为nil), 不再指向销毁的对象(永远不会产生野指针错误)
- 用途
- assign一般用在基本数据类型上面, 比如int\double等
- weak一般用在代理对象上面, 或者用来解决循环强引用的问题
3、深拷贝(mutableCopy)和浅拷贝(copy):
深拷贝就是内容拷贝,浅拷贝就是指针拷贝。
copy vs retain
retain和strong都是指针拷贝。当有其他对象引用当前对象时,会拷贝一份当前对象的地址,这样它就也指向当前对象了。所以,还是同一个对象,只是retainCount+1;
copy:对于不可变对象copy采用的是浅复制,引用计数器加1(其实这是编译器进行了优化,既然原来的对象不可变,复制之后的对象也不可变那么就没有必要再重新创建一个对象了);对于可变对象copy采用的是深复制,引用计数器不变(原来的对象是可变,现在要产生一个不可变的当然得重新产生一个对象);
浅复制如下:
NSString *str1 = @"123";
NSString *str2 = [str1 copy];4、xib跟storyboard拖得控件一般为 weak 而不是 strong
4、xib跟storyboard拖的控件一般为weak而不是strong
我们平时定义控件属性的时候一般都会用strong修饰符,而我们在用xib,sb拖控件的时候会发现,这时属性都是用的weak修饰符。
UIViewController->UIView->subView->UIButton
然后你为这个UIButton声明一个weak属性
@property(nonatomic,weak) IBOOutlet UIButton *btn;
2.手动创建控件
a). 将控件声明成strong
@property(nonatomic,strong) UIButton *btn;
_btn = [[UIButton alloc]init];
[self.view addSubview:_btn]
b). 将控件声明成weak
@property(nonatomic,weak) UIButton *btn;
UIButton *button = [[UIButton alloc]init];
_btn = button;
[self.view addSubview:_btn];
最近看的黑马iOS视频上给的建议的是:
1.如果用Stroyboard拖线,用weak
2.如果自定对象,用strong
事实上IBOutlet的属性一般可以设为weak是因为它已经被view引用了,除非view被释放,否则IBOutlet的属性也不会被释放,另外IBOutlet属性的生命周期和view应该是一致的,所以IBOutlet属性一般设为weak。
5、避免“强引用循环“的僵局:
默认的引用方式是强引用,但上面说了有时我们还得使用弱引用,那是什么情况呢?
答案,强引用循环:A对象强引用了B对象,B对象也强引用了A。因为都是强引用,也就是无论是A是B都要在对方的引用断了后才能销毁,但要断了引用,就必须对方对象销毁。就会出现这种僵局,为了避免出现这种情况,就应该有一个对象“示弱”,使其为“弱引用”。
比较常见的,视图中的父子视图之间的引用:父视图强引用子视图,子视图弱引用父视图。