美文网首页
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深拷贝PK浅拷贝,欢迎来战!

    OC深拷贝PK浅拷贝,欢迎来战! OC深拷贝PK浅拷贝,欢迎来战!

  • copy和mutableCopy的区别

    copy和mutableCopy的区别 深拷贝和浅拷贝的区别 在OC中对象的拷贝方式有两种:深拷贝和浅拷贝.浅拷贝...

  • iOS 中浅拷贝,深拷贝和完全深拷贝

    先说结论:OC中有浅拷贝和深拷贝,浅拷贝只是对地址的引用,深拷贝是单独复制一份,两者地址不同。但是OC中的深拷贝并...

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • ios 关于深拷贝和浅拷贝的深入理解

    OC 语言的拷贝分三种:浅拷贝,不完全深拷贝,完全深拷贝,来让我们举个?: 1.浅拷贝:没有开辟新的指针地址,只是...

  • oc 浅拷贝与深拷贝

    1. 先说结论: 分可变对象、不可变对象、自定义对象、容器对象几种: 例子参考: iOS开发——深拷贝与浅拷贝详...

  • oc深拷贝与浅拷贝

    属性对应的所有权修饰符: assign __unsafe_unretained copy __strong(赋值...

  • 认识js下的浅拷贝与深拷贝

    浅拷贝与深拷贝 首先深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅拷贝只拷贝一...

  • OC的深拷贝与浅拷贝

    Objective-C 对象是通过指向该对象内存地址的指针,以间接方式访问的。 指针赋值: MRC 下仅仅将一个新...

  • 深拷贝和浅拷贝

    干货!深拷贝和浅拷贝的区别 深拷贝才是拷贝,浅拷贝就是Retain Copy与Retain的区别 Copy: 根据...

网友评论

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

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