浅拷贝:拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象。
浅拷贝.png
NSString *str1 = @"str1";
NSString *str2 = [str1 copy];
NSLog(@"\nstr1 = %@ str1P = %p \n str2 = %@ str2P = %p", str1, str1, str2, str2);
/*输出结果
str1 = str1 str1P = 0x104d75180
str2 = str1 str2P = 0x104d75180
*/
深拷贝:拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。
深拷贝.png
NSMutableString *mStr1 = [NSMutableString stringWithString:@"123"];
NSMutableString *mStr2 = [mStr1 mutableCopy];
NSLog(@"\n mStr1 = %@ mStr1P = %p \n mStr2 = %@ mStr2P = %p", mStr1, mStr1, mStr2, mStr2);
/*输出结果
mStr1 = 123 mStr1P = 0x6000004460c0
mStr2 = 123 mStr2P = 0x600000446420
*/
开辟了新的内存空间
可变对象NSMutableString
- (void) mutableNSStringTest
{
NSMutableString *mstr1 = [NSMutableString stringWithString:@"test002"];
NSMutableString *mstr2 = [mstr1 copy];
//[str2 appendString:@"test"]; //copy返回的是不可变对象,mstr2不能被修改,因此会发生崩溃
NSMutableString *mstr3 = [mstr1 mutableCopy];
[mstr3 appendString:@"modify"];
NSLog(@"mstr1:%p - %@ \r\n",mstr1,mstr1);
NSLog(@"mstr2:%p - %@ \r\n",mstr2,mstr2);
NSLog(@"mstr3:%p - %@ \r\n",mstr3,mstr3);
}
2017-07-20 18:14:35.789 beck.wang[1433:180881] mstr1:0x610000075e40 - test002
2017-07-20 18:14:35.790 beck.wang[1433:180881] mstr2:0xa323030747365747 - test002
2017-07-20 18:14:35.790 beck.wang[1433:180881] mstr3:0x610000074480 - test002modify
分析:mstr1、mstr2、mstr3 地址都不同,NSMutableString对象copy与mutableCopy都是深拷贝,且copy返回的对象是不可变对象。
总结一波:copy不可变对象时是浅拷贝,copy可变对象时是深拷贝,mutableCopy是深拷贝
再来看一段代码
NSString *str1 = @"str1";
NSString *str2 = [str1 copy];
str1 = @"asdf";
NSLog(@"\nstr1 = %@ str1P = %p \n str2 = %@ str2P = %p", str1, str1, str2, str2);
/*输出结果,修改str2 同理
str1 = asdf str1P = 0x10776b1a0
str2 = str1 str2P = 0x10776b180
*/
这里不是说copy是浅拷贝吗?str1 和 str2 指向同一个内存空间,str1变化,str2的值也会变化。
但是copy还有它的特点:
修改源对象的属性和行为,不会影响副本对象
修改副本对象的属性和行为,不会影响源对象
自定义类实现copy的步骤:
(1)遵守NSCoping协议
(2)实现copyWithZone方法。//参数zone基本不用,它的意思是指定该方法从始至终都在某一个区域分配内存
(所有copy最终都会调用这个方法)
{
//方法内部进行以下操作
//(1)实例化对象
A* a = [A alloc ]init]; //一般正规写法是[[self.class alloc] init] 因为这样子类也可以复用该方法
//(2)给属性赋值
a.xx = xx;
//(3)返回新对象
return a;
}
#import <Foundation/Foundation.h>
/*
创建一个Teacher类,并让该类实现copy方法
*/
//1.遵守NSCopying协议
@interface Teacher : NSObject<NSCopying>
@property(nonatomic,copy)NSString* name;
//2.实现copyWithZone方法;
-(id)copyWithZone:(NSZone *)zone;
@end
#import "Teacher.h"
@implementation Teacher
//实现copyWithZone方法
-(id)copyWithZone:(NSZone *)zone
{
Teacher* teacher = [[self.class alloc]init];
teacher.name = self.name;
return teacher;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Teacher* teacher = [[Teacher alloc]init];
teacher.name = @"我是园丁";
Teacher* teacher1 = [teacher copy];
NSLog(@"teacher:%p-%@",teacher,teacher.name);
NSLog(@"teacher1:%p-%@",teacher1,teacher1.name);
}
运行结果:
2015-08-15 16:41:07.821 copy的那些事[1779:148657] teacher:0x7fd750d13ce0-我是园丁
2015-08-15 16:41:07.822 copy的那些事[1779:148657] teacher1:0x7fd750d13cf0-我是园丁
上面代码如果没有实现NSCopying协议,-[Person copyWithZone:]: unrecognized selector sent to instance 0x60000022b6a0
网友评论