zoukankan      html  css  js  c++  java
  • Objective-C 谈谈深浅拷贝,copy和mutable copy都不是完全拷贝

    (一)字符串中的指针赋值,copy和mutablecopy

       NSString和NSString

     (1)指针赋值

        肯定指向同一个字符串地址。

       (2)copy(和直接指向一样)

        NSString *str1=@"aaa";
        NSString *str2=[str1 copy];
        NSLog(@"str1:%p----str2:%p",&str1,&str2);//指针地址输出,不一样,说明指针新建了
        NSLog(@"str1:%p----str2:%p",str1,str2);//指针指向内容地址输出,是一样的,说明内容没有被拷贝

      结果说明Copy也没实现拷贝,说明以下情况都是等价的,都指向同个内存区域

      NSString *str2=str1;
      NSString *str3 = [[NSString alloc]initWithString:str1];
      NSString *str4 = [NSString stringWithString:str1];
    NSString *str5 = [str1 copy];

          如果场景需要,比如为了让某个str1指向的地方销毁,要先拷贝到新地址,然后用str2指,可以对NSString进行拷贝。

       (3)mutablecopy(实现了拷贝)

        NSString *str1=@"aaa";
        NSString *str2=[str1 mutableCopy];
        NSLog(@"str1:%p----str2:%p",&str1,&str2);//指针地址输出,不一样,说明指针新建了
        NSLog(@"str1:%p----str2:%p",str1,str2);//指针指向内容地址输出,是不一样的,说明重新开辟了内存,把str1的内容拷贝到新内存,str2变量指向这个新地址
    

       NSMutableString到NSMutableString

          (1)指针赋值:

           肯定指向同一个可变字符串地址。

           (2)mutablecopy

        NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
        NSMutableString *mStr2=[mStr mutableCopy];
        NSLog(@"mstr:%p-----mstr2:%p",mStr,mStr2);//指针内容地址不一样,说明实现了拷贝
        [mStr2 appendString:@"def"];
        NSLog(@"mstr:%@-----mstr2:%@",mStr,mStr2);//互不相干
    

     此种方式实现了对NSMutableString的拷贝,产生两个互不相干的可变字符串。

            (3)copy( 错误,会崩)

        NSMutableString *mStr2=[mStr copy];
    

       

        NSMutableString到NSString

       (1)指针赋值:

        NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
        NSString *str=mStr;
        NSLog(@"mstr:%p-----str:%p",mStr,str);//指针指向内容地址一样,说明mStr的改变会联动str
        [mStr appendString:@"def"];
        NSLog(@"mstr:%@-----str:%@",mStr,str);//mStr的改变影响了str
    

     这种情况,mStr的改变会影响str,但str改变就会重新指向,并不会影响mStr

       (2)copy和mutablecopy:

        NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];
        NSString *str=[mStr copy];//NSString *str=[mStr mutableCopy];也能实现
        NSLog(@"mstr:%p-----str:%p",mStr,str);
    

    这种情况,str对mStr进行拷贝,mStr改变不影响str。

    但这里面,[mStr copy]和[mstr mutableCopy],虽然都对原mStr进行了拷贝,开辟了新内存区域,但区别在于前者拷贝的对象是不可变的,后者的是可变的。可变字符串赋值给NSString其实也就丧失动态性了。

        NSString到NSMutableString

        用copy方法,让NSString给NSMutableString赋值的也是作死行为,应该使用StringWithString方法初始化NSMutableString

        NSString *str1=@"str1";
        NSMutableString *mStr=[str1 copy];
        [mStr appendFormat:@"abc"];
    

      

    总结一下:

    1.NSString之间,copy并不能实现拷贝(等同直接指向),必须mutablecopy实现拷贝

    2.NSMutableString之间,Mutablecopy实现拷贝。

    3.对于NSMutableString拷贝给NSString,copy和mutablecopy都能完成任务。 

    所以:对于字符串之间的拷贝,必须Mutablecopy才能实现拷贝。

    数组变量赋值时的直接指向,copy和mutablecopy

         NSArray和NSArray

       (1)直接指向

        肯定是指向同个数组。

       (2)copy

        NSArray *array1=[NSArray arrayWithObjects:@"1",@"2",@"3",nil];
        NSArray *array2=[array1 copy];
        NSLog(@"arr1:%p,arr2:%p",&array1,&array2);//指针地址不同,说明是2个不一样的指针变量
    NSLog(@"arr1:%p,arr2:%p",array1,array2);//数组指针指向内容相同,说明copy方法对NSArray而言,依旧是直接指向,并无拷贝
    NSLog(@"arr1:%p,arr2:%p",array1[0],array2[0]);//数组地址相同,内容地址肯定相同了

        说明copy也没实现拷贝,依旧指向同个数组。

         (3)mutablecopy

        NSArray *array1=[NSArray arrayWithObjects:@"1",@"2",@"3",nil];
        NSArray *array2=[array1 mutableCopy];
        NSLog(@"arr1:%p,arr2:%p",&array1,&array2);//不同指针变量,地址不同
        NSLog(@"arr1:%p,arr2:%p",array1,array2);//数组地址不同,说明数组实现了拷贝
        NSLog(@"arr1:%p,arr2:%p",array1[0],array2[0]);//元素地址相同,说明元素并没有被拷贝

         说明实现了拷贝,但数组内元素的指针被拷贝,但元素并没有被拷贝。

       NSMutableArray和NSMutableArray

        (1)直接指向

          同一个嘛。肯定一起改。

        (2)mutablecopy

        NSMutableArray *mArray1=[NSMutableArray arrayWithObjects:
                                 [NSMutableString stringWithString:@"1"],
                                 [NSMutableString stringWithString:@"2"],
                                 [NSMutableString stringWithString:@"3"],nil];
        NSMutableArray *mArray2=[mArray1 mutableCopy];
        NSLog(@"arr1:%p,arr2:%p",&mArray1,&mArray2);//指针地址不同,说明是2个不一样的指针
        NSLog(@"arr1:%p,arr2:%p",mArray1,mArray2);//数组地址不同,说明数组得到了拷贝
        NSLog(@"arr1:%p,arr2:%p",mArray1[0],mArray2[0]);//内容地址相同,说明内容并没有拷贝
    

          说明mutablecopy实现了拷贝,但没有实现数组内部元素的拷贝。

          这种内容为可变元素的情况下,如果对可变数组1元素改变,可变数组2元素也会一起改。并没有实现完全拷贝。要实现完全拷贝,就要继续一层层剥开,全部拷贝再重组数组。

          说明:

          1.和NSString一样,NSArray的copy方法其实都没有实现一丁点拷贝(和直接指向是一样的),只有Mutablecopy才能实现拷贝。

          2.但mutablecopy只是拷贝了数组本身和数组中每个元素的指针,并没有实现数组元素的拷贝。

            

    自定义类实现NSCopying和NSMutableCopying协议

    如果没有实现这两个协议,copy和mutablecopy方法都是不会得到响应的,并且具体拷贝的程度,也和具体实现有关 

    新建Student类

    .h

    #import <Foundation/Foundation.h>
    
    @interface Student : NSObject<NSCopying,NSMutableCopying>
    
    @property (copy) NSString *name;
    @property (copy) NSString *age;
    @property (strong) NSMutableArray *GradeArray;
    @end

     .m

    #import "Student.h"
    
    @implementation Student
    
    -(id)initWithName:(NSString *)name GradeArray:(NSMutableArray *)gradeArray{
        self=[super init];
        if (self) {
            self.name=name;
            self.GradeArray=gradeArray;
        }
        return self;
    }
    
    -(id)copyWithZone:(NSZone *)zone
    {
        Student *stu = [[Student allocWithZone:zone] initWithName:self.name GradeArray:self.GradeArray];
        return stu;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone{
        Student *stu = [[Student allocWithZone:zone] initWithName:self.name GradeArray:self.GradeArray];
        return stu;
    }
    
    @end
    

    copy:

        Student *stu1=[[Student alloc]init];
        stu1.name=@"stu1";
        stu1.GradeArray=[[NSMutableArray alloc]init];
        [stu1.GradeArray addObject:@"100"];
        Student *stu2=[stu1 mutableCopy];
        NSLog(@"stu1:%p----stu2:%p",stu1,stu2);//stu1:0x7faa43c1b050----stu2:0x7faa43c1d0d0
        NSLog(@"stu1:%p----stu2:%p",stu1.name,stu2.name);//stu1:0x10df5f080----stu2:0x10df5f080
        NSLog(@"stu1:%p----stu2:%p",stu1.GradeArray,stu2.GradeArray);//stu1:0x7faa43c1ad40----stu2:0x7faa43c1ad40
    

    说明对象拷贝了,但成员的指针所指内容并没有拷贝。

    对于自定义对象,最深的拷贝也只能到拷贝成员指针的程度了,说明copy和mutablecopy都不是完全拷贝

    总结下,如果要对某个对象实现完全拷贝:

    1.必须分别对Class里的每个对象进行mutablecopy(对于基本数据对象,copy不一定行哦)

    2.并且如果Class里存在容器性质的对象(比如Array和MutableArray),目前只是拷贝了该数组,没有拷贝可变数组里的元素所指内容,要完全拷贝得再深挖进去,对该mutableArray的每个元素进行mutablecopy

    直到对非容器性质的对象进行mutablecopy后才算完全拷贝

        Student *stu1=[[Student alloc]init];
        stu1.name=@"stu1";
        stu1.GradeArray=[[NSMutableArray alloc]init];
        [stu1.GradeArray addObject:@"100"];
        Student *stu2=[stu1 mutableCopy];
        stu2.name=[stu1.name mutableCopy];
        stu2.GradeArray=[stu1.GradeArray mutableCopy];
        NSLog(@"stu1:%p----stu2:%p",stu1,stu2);//stu1:0x7faa43c1b050----stu2:0x7faa43c1d0d0
        NSLog(@"stu1:%p----stu2:%p",stu1.name,stu2.name);//stu1:0x10df5f080----stu2:0x10df5f080
        NSLog(@"stu1:%p----stu2:%p",stu1.GradeArray,stu2.GradeArray);//stu1:0x7faa43c1ad40----stu2:0x7faa43c1ad40
    

     所以一个比较好的方法就是像上个博客里面说的,遵循NSCoding协议,先归档(序列化),再解开(反序列化)

        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:stu1];
        Student *stu2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    

     啊完全拷贝啊~~一切都清净了。。。

  • 相关阅读:
    SAM4E单片机之旅——2、LED闪烁之轮询定时器
    SAM4E单片机之旅——1、LED闪烁之空循环
    C#使用WinAPI 修改电源设置,临时禁止笔记本合上盖子时睡眠
    阻止系统自动睡眠的小软件,附C#制作过程
    Python3做采集
    判断浏览器类型
    任意几个数求和
    常见Z纯CSS小样式合集(三角形)
    数据脱敏项目中遇见的问题
    点击左侧跳到右侧
  • 原文地址:https://www.cnblogs.com/rayshen/p/5009583.html
Copyright © 2011-2022 走看看