美文网首页
OC的深拷贝与浅拷贝

OC的深拷贝与浅拷贝

作者: 苏沫离 | 来源:发表于2020-05-08 20:43 被阅读0次

    Objective-C 对象是通过指向该对象内存地址的指针,以间接方式访问的。

    指针赋值:

    • MRC 下仅仅将一个新的指针指向该内存地址,并没有获取该内存的所有权,引用计数不变;
    • ARC 下由于默认使用 strong 修饰,因此将一个新的指针指向该内存地址,获取该内存的所有权,引用计数+1;

    对于实现了NSCopying与NSMutableCopying协议的对象来说,指针赋值并非简单的赋值,还有额外的操作:

    • 浅拷贝:类似于ARC下的指针赋值,将一个新指针指向该内存地址;
    • 深拷贝:将一个新指针指向新的内存对象,该内存的数据与被复制的数据相同!如果改变原内存数据,新对象不会随着改变!

    2、非容器类与容器类

    2.1、非容器类 NSString

    系统类 NSString 实现了 NSCopyingNSMutableCopying 协议

    2.1.1、不可变对象 NSString
    {
        NSString *string = [[NSString alloc] initWithString:@"String"];
        NSString *string_1 = string;
        NSString *string_2 = [string copy];
        NSString *string_3 = [string mutableCopy];
        NSLog(@"string     : %@",logString(string));
        NSLog(@"string_1   : %@",logString(string_1));
        NSLog(@"string_2   : %@",logString(string_2));
        NSLog(@"string_3   : %@",logString(string_3));
    }
    
    /** 打印日志
    string     : String  0x1070701a8 |  rCount :-1 | __NSCFConstantString
    string_1   : String  0x1070701a8 |  rCount :-1 | __NSCFConstantString
    string_2   : String  0x1070701a8 |  rCount :-1 | __NSCFConstantString
    string_3   : String  0x600003f381e0 |  rCount :1 | __NSCFString
     */
    
    2.1.2、可变对象 NSMutableString
    {
        NSMutableString *mString = [[NSMutableString alloc] initWithString:@"Mutable String"];
        NSString *mString_1 = mString;
        NSString *mString_2 = [mString copy];
        NSString *mString_3 = [mString mutableCopy];
        NSLog(@"mString     : %@",logString(mString));
        NSLog(@"mString_1   : %@",logString(mString_1));
        NSLog(@"mString_2   : %@",logString(mString_2));
        NSLog(@"mString_3   : %@",logString(mString_3));
    }
    /** 打印日志
    mString     : Mutable String  0x600003f10840 |  rCount :1 | __NSCFString
    mString_1   : Mutable String  0x600003f10840 |  rCount :1 | __NSCFString
    mString_2   : Mutable String  0x60000316d420 |  rCount :1 | __NSCFString
    mString_3   : Mutable String  0x600003f12160 |  rCount :1 | __NSCFString
     */
    
    操作 非容器类 NSString NSMutableString
    copy 类似于ARC下的指针赋值 深拷贝,得到一个可变对象
    mutableCopy 深拷贝,得到一个可变对象 深拷贝,得到一个可变对象
    2.2、容器类 NSArrayNSDictionary
    2.2.1、容器类 NSArray
    {
        NSString *string = @"String";
        NSMutableString *mString = [[NSMutableString alloc] initWithString:@"Mutable String"];
        NSLog(@"string  :  %@",logString(string));
        NSLog(@"mString :  %@",logString(mString));
        
        NSArray *array = [[NSArray alloc] initWithObjects:string,mString, nil];
        NSMutableArray *mArray = [[NSMutableArray alloc] initWithObjects:string,mString, nil];
        
        mString.string = @"Mutable String_2";
        NSLog(@"mString :  %@",logString(mString));
        
        NSArray *array_1 = array;
        NSArray *array_2 = [array copy];
        NSArray *array_3 = [array mutableCopy];
        NSLog(@"array     : %@",logArray(array));
        NSLog(@"array_1   : %@",logArray(array_1));
        NSLog(@"array_2   : %@",logArray(array_2));
        NSLog(@"array_3   : %@",logArray(array_3));
        
        printf("\n  \n");
        NSMutableArray *mArray_1 = mArray;
        NSMutableArray *mArray_2 = [mArray copy];
        NSMutableArray *mArray_3 = [mArray mutableCopy];
        NSLog(@"mArray     : %@",logArray(mArray));
        NSLog(@"mArray_1   : %@",logArray(mArray_1));
        NSLog(@"mArray_2   : %@",logArray(mArray_2));
        NSLog(@"mArray_3   : %@",logArray(mArray_3));
    }
    /** 打印日志:
    string  :  String  0x10aa001a8 |  rCount :-1 | __NSCFConstantString
    mString :  Mutable String  0x600002c4e550 |  rCount :1 | __NSCFString
    mString :  Mutable String_2  0x600002c4e550 |  rCount :3 | __NSCFString
    array     :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x6000022485e0 | rCount :2 | __NSArrayI
    array_1   :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x6000022485e0 | rCount :2 | __NSArrayI
    array_2   :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x6000022485e0 | rCount :2 | __NSArrayI
    array_3   :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x600002c463d0 | rCount :1 | __NSArrayM
    
      
    mArray     :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x600002c44000 | rCount :1 | __NSArrayM
    mArray_1   :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x600002c44000 | rCount :1 | __NSArrayM
    mArray_2   :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x6000022408c0 | rCount :1 | __NSArrayI
    mArray_3   :
          String :0x10aa001a8
          Mutable String_2 :0x600002c4e550
      0x600002c78ff0 | rCount :1 | __NSArrayM
    */
    
    2.2.2、容器类NSDictionary
    {
        NSString *string = @"String";
        NSMutableString *mString = [[NSMutableString alloc] initWithString:@"Mutable String"];
        NSLog(@"string  :  %@",logString(string));
        NSLog(@"mString :  %@",logString(mString));
        
        NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:string,@"NSString",mString,@"NSMutableString", nil];
        NSMutableDictionary *mDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:string,@"NSString",mString,@"NSMutableString", nil];
        
        NSDictionary *dict_1 = dict;
        NSDictionary *dict_2 = [dict copy];
        NSDictionary *dict_3 = [dict mutableCopy];
        NSLog(@"dict    : %@",logDictionary(dict));
        NSLog(@"dict_1  : %@",logDictionary(dict_1));
        NSLog(@"dict_2  : %@",logDictionary(dict_2));
        NSLog(@"dict_3  : %@",logDictionary(dict_3));
        
        printf("\n  \n");
        NSMutableDictionary *mDict_1 = mDict;
        NSMutableDictionary *mDict_2 = [mDict copy];
        NSMutableDictionary *mDict_3 = [mDict mutableCopy];
        NSLog(@"mDict    : %@",logDictionary(mDict));
        NSLog(@"mDict_1  : %@",logDictionary(mDict_1));
        NSLog(@"mDict_2  : %@",logDictionary(mDict_2));
        NSLog(@"mDict_3  : %@",logDictionary(mDict_3));
    }
    
    /** 打印日志
    string  :  String  0x10fba11a8 |  rCount :-1 | __NSCFConstantString
    mString :  Mutable String  0x600003859f20 |  rCount :1 | __NSCFString
    dict    :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600002360700 | rCount :2 | __NSDictionaryI
    dict_1  :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600002360700 | rCount :2 | __NSDictionaryI
    dict_2  :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600002360700 | rCount :2 | __NSDictionaryI
    dict_3  :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600003611da0 | rCount :1 | __NSDictionaryM
       
    mDict    :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600003611600 | rCount :1 | __NSDictionaryM
    mDict_1  :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600003611600 | rCount :1 | __NSDictionaryM
    mDict_2  :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600003650860 | rCount :1 | __NSFrozenDictionaryM
    mDict_3  :
        NSString String :0x10fba11a8
        NSMutableString Mutable String :0x600003859f20
       0x600003650800 | rCount :1 | __NSDictionaryM
     */
    
    操作 NSArrayNSDictionary NSMutableArrayNSMutableDictionary 容器中元素
    copy 浅拷贝,类似于ARC下的指针赋值 深拷贝,得到一个不可变对象 浅拷贝
    mutableCopy 深拷贝,得到一个可变对象 深拷贝,得到一个可变对象 浅拷贝

    3、NSString 类型的属性修饰符

    什么时候使用 copy 修饰 NSString 类型的属性?什么时候使用 strong 修饰 NSString 类型的属性?

    @property (nonatomic ,strong) NSString *sString;
    @property (nonatomic ,copy) NSString *cString;
    

    3.1、赋值NSMutableString常量

    {
        NSMutableString *mString = [[NSMutableString alloc] initWithString:@"Mutable String"];
        self.sString = mString;
        self.cString = mString;
        NSLog(@"mString   : %@ : %p : %p : %ld",mString,mString,&mString,mString.retainCount);
        NSLog(@"sString   : %@ : %p : %p : %ld",self.sString,self.sString,&_sString,_sString.retainCount);
        NSLog(@"cString   : %@ : %p : %p : %ld",self.cString,self.cString,&_cString,_cString.retainCount);
        
        mString.string = @"Mutable String_1";
        NSLog(@"mString   : %@ : %p : %p : %ld",mString,mString,&mString,mString.retainCount);
        NSLog(@"sString   : %@ : %p : %p : %ld",self.sString,self.sString,&_sString,_sString.retainCount);
        NSLog(@"cString   : %@ : %p : %p : %ld",self.cString,self.cString,&_cString,_cString.retainCount);
        
        mString = [[NSMutableString alloc] initWithString:@"Mutable String_2"];
        NSLog(@"mString   : %@ : %p : %p : %ld",mString,mString,&mString,mString.retainCount);
        NSLog(@"sString   : %@ : %p : %p : %ld",self.sString,self.sString,&_sString,_sString.retainCount);
        NSLog(@"cString   : %@ : %p : %p : %ld",self.cString,self.cString,&_cString,_cString.retainCount);    
    }
    
    /** 打印日志
    mString   : Mutable String : 0x600002f19650 : 0x7ffee5f1a138 : 2
    sString   : Mutable String : 0x600002f19650 : 0x7fad5cf0d800 : 2
    cString   : Mutable String : 0x600002135d40 : 0x7fad5cf0d808 : 1
    
    mString   : Mutable String_1 : 0x600002f19650 : 0x7ffee5f1a138 : 2
    sString   : Mutable String_1 : 0x600002f19650 : 0x7fad5cf0d800 : 2
    cString   : Mutable String : 0x600002135d40 : 0x7fad5cf0d808 : 1
    
    mString   : Mutable String_2 : 0x600002f0c1b0 : 0x7ffee5f1a138 : 1
    sString   : Mutable String_1 : 0x600002f19650 : 0x7fad5cf0d800 : 2
    cString   : Mutable String : 0x600002135d40 : 0x7fad5cf0d808 : 1
     */
    

    NSMutableString *mString 赋值给上述属性 cStringsString

    • copy 修饰的变量cString属于深拷贝,使用新的指针指向新的内存地址,新的内存地址存储的数据与被赋值的数据相同;
    • strong 修饰的变量sString属于浅拷贝,使用新的指针指向被赋值变量的内存地址,类似于 retain 操作,引用计数 +1;

    改变 mString.string 的值:

    • 由于变量cString属于深拷贝,不被 mString 的操作影响;
    • strong 修饰的变量仍然指向 mString 的内存,因此该变量的字符串也被改变;

    mString 指向别处:

    • 由于变量cString属于深拷贝,不被 mString 的操作影响;
    • strong 修饰的变量仍然指向原有内存,值不改变;

    3.2、赋值NSString常量

    {        
        NSString *string = @"Hello Word!";
        self.sString = string;
        self.cString = string;
        NSLog(@"string   : %@ : %p : %p : %ld",string,string,&string,string.retainCount);
        NSLog(@"sString   : %@ : %p : %p : %ld",self.sString,self.sString,&_sString,_sString.retainCount);
        NSLog(@"cString   : %@ : %p : %p : %ld",self.cString,self.cString,&_cString,_cString.retainCount);
            
        string = @"hehe";
        NSLog(@"string   : %@ : %p : %p : %ld",string,string,&string,string.retainCount);
        NSLog(@"sString   : %@ : %p : %p : %ld",self.sString,self.sString,&_sString,_sString.retainCount);
        NSLog(@"cString   : %@ : %p : %p : %ld",self.cString,self.cString,&_cString,_cString.retainCount);
    }
    
    /** 打印日志
    string   : Hello Word! : 0x109ce5608 : 0x7ffee5f1a130 : -1
    sString   : Hello Word! : 0x109ce5608 : 0x7fad5cf0d800 : -1
    cString   : Hello Word! : 0x109ce5608 : 0x7fad5cf0d808 : -1
    
    string   : hehe : 0x109ce5648 : 0x7ffee5f1a130 : -1
    sString   : Hello Word! : 0x109ce5608 : 0x7fad5cf0d800 : -1
    cString   : Hello Word! : 0x109ce5608 : 0x7fad5cf0d808 : -1
     */
    

    NSString *string 赋值给上述属性 cStringsString:都是浅拷贝,类似于 retain 操作,引用计数 +1;
    改变变量 string 的值,即将指针 string 指向别的内存地址;此时变量cStringsString 指向原有内存,值不改变;

    结论:

    • 如果不希望属性变量 string 的值随着 NSMutableString 变化,就用copy来修饰string属性;
    • 如果需要属性变量 string 的值随着 NSMutableString 变化而改变,就用strong来修饰string

    Demo

    相关文章

      网友评论

          本文标题:OC的深拷贝与浅拷贝

          本文链接:https://www.haomeiwen.com/subject/ospxwhtx.html