iOS浅拷贝和深拷贝

2018-11-30  本文已影响14人  Jey

浅拷贝:拷贝指向原来对象的指针,使原对象的引用计数+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

上一篇下一篇

猜你喜欢

热点阅读