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一般用在基本数据类型上面, 比如intdouble等

- 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修饰符。

1. 从storyboard或者xib上创建控件,在控件放在view上的时候,已经形成了如下的引用关系,以UIButton为例:
UIViewController->UIView->subView->UIButton
然后你为这个UIButton声明一个weak属性
@property(nonatomic,weak) IBOOutlet UIButton *btn;
相当于xib/sb对这个Button是强引用,你声明的属性对它是弱引用。

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都要在对方的引用断了后才能销毁,但要断了引用,就必须对方对象销毁。就会出现这种僵局,为了避免出现这种情况,就应该有一个对象“示弱”,使其为“弱引用”。

  比较常见的,视图中的父子视图之间的引用:父视图强引用子视图,子视图弱引用父视图。

原文地址:https://www.cnblogs.com/dannygao/p/6958909.html