1、声明block的时候都是用copy来修饰的原因:
block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。
使用retain也可以,但是block的retain行为默认是用copy的行为实现的,因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。
2、NSString到底是用copy还是strong修饰比较好?
本质上来讲,copy和strong都没有错,但不是说,NSString用copy就一定是最好的。这里面涉及到了性能和安全的问题,我们可以区别对待:copy修饰的NSString,在初始化时,如果来源是NSMutableString的话,会对来源进行一次深拷贝,将来源的内存地址复制一份,这样,两个对象就一点关系就没有了,无论你怎么操作来源,都不会对自己的NSString有任何影响。而strong是浅拷贝的,并不会对来源的内存地址进行拷贝,当我们操作来源时,NSString也会随之改变。
copy修饰的NSString在进行set操作时,底层是如何实现的呢?
我们举个例子 str = sourceStr 时str用copy修饰,内部会执行一个操作:
str = [sourceStr copy];
那么这个copy里面做了什么呢?
if ([sourceStr isMemberOfClass:[NSMutableString class]])
没错,就是进行一次判断,判断来源是可变的还是不可变的,如果是不可变,接下来的操作就跟strong修饰的没有区别,进行浅拷贝;如果是可变的,那么会进行一次深拷贝。所以,copy操作内部会进行判断,别小看了这个if操作所消耗的内存,一次不重要,十次可能也可以忽略不计,但当你的项目十分庞大时,有成百上千个个NSString对象,多多少少会对你的app的性能造成一定的影响。
所以当给NSString对象赋值时,如果来源是NSMutableString,那么这种情况就必须要用copy;如果你确定来源是不可变类型的,那么用strong比较好。
3、深拷贝与浅拷贝
浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象。深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。深拷贝就是内容拷贝,浅拷贝就是指针拷贝。本质区别在于:
- 是否开启新的内存地址;
- 是否影响内存地址的引用计数;
请记住:
- 可变对象的copy和mutableCopy方法都是深拷贝。
- 不可变对象的copy方法是浅拷贝,mutableCopy方法是深拷贝。
- copy方法返回的对象都是不可变对象。
4、