结论
一.如何区分[obj copy]是深拷贝还是浅拷贝?
1.当不可变类型对象调用copy拷贝后,不会产生新的对象,属于浅拷贝;
2.其他类型对象调用copy,都会产生新的不可变对象,属于深拷贝(遵循NSCopy协议并重写copyWithZone方法);
3.无论什么类型的对象,调用mutableCopy方法后, 都会产生新的可变对象, 但这不是属性特质的东西.
深浅拷贝完整的有demo的解析:http://blog.csdn.net/Mazy_ma/article/details/51899397
二.如何重写strong, copy属性的set方法
以dog.h文件的name属性为例:
ARC环境里
1.如果是strong, 则直接赋值
- (void)setName:(NSString *)name {
_name = name
}
2.如果是copy, 则执行copy操作
- (void)setName:(NSString *)name {
_name = [name copy];//系统会自动判断并执行"深或浅拷贝"
}
MRC环境下
I.如果是strong(即retain), 则
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name retain];//引用计数+1
}
}
II.如果是copy, 则
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name copy];//系统自动判断"深或浅"拷贝
}
}
//有人说,为什么都需要做if判断?
//解析:因为如果_name和name指针指向的是同一个对象时,
//先执行的release操作可能导致"对象"引用计数为0,程序崩溃.
我的Demo代码:
ARC下
Dog.h文件
#import <Foundation/Foundation.h>
@interface Dog : NSObject
@property (nonatomic, strong) NSString *strongName;
@property (nonatomic, copy) NSString *cobyName;
//Dog.m无须实现
@end
控制器代码
#import "ViewController.h"
#import "Dog.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
#pragma mark - 当原对象是"固定对象"=不可变对象(此时的copy与strong是一样的,都是浅拷贝)
NSString *oldStr = @"qpj";
Dog *dd = [[Dog alloc]init];
dd.strongName = oldStr;
NSLog(@"strongName1:%@", dd.strongName);//qpj
//修改oldStr
oldStr = @"123";
NSLog(@"strongName2:%@", dd.strongName);//qpj
//思考:为什么还是输出qpj? 是苹果的错误?
//答: oldStr指向了另一个对象了, 并没有修改原对象@"qpj", 所以输出的是qpj
//所以,对于cobyName,同上!
//结论:没有讨论的必要,因为所有对象本质都是不可变的!
#pragma mark - 当原对象是可变类型的(网络数据/DB数据)
// 定义一个可变的字符,作为小狗的name
NSMutableString *oo = [@"dakongyi" mutableCopy];
Dog *dog = [[Dog alloc] init];
dog.strongName = oo;
dog.cobyName = oo;
// 当小狗的name值发生改变时
[oo appendString:@"HH"]; // oo ==> "dakongyiHH"
//
NSLog(@"原对象可变时-strong属性:%@",dog.strongName);// 打印结果:dakongyiHH
//
NSLog(@"原对象可变时-copy属性:%@",dog.cobyName);// 打印结果:dakongyi
//结论:strong是浅拷贝; copy在此处是深拷贝
拓展:请写出copy和strong的set方法:
//分析:这时候,应该需要区分原对象是否'可变'!
//对于strong, 不管是否原对象可变,都是直接赋值_name=name,
//对于copy, 如果原对象不可变, 应该执行浅拷贝, 如果对象可变,应该执行深拷贝,即总结
//_name = [name copy];//系统自己判断深浅拷贝copy
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end