심층 복사와 얕은 복사 사열

12164 단어
wenghengcong.com

하나.기본 유형의 복제본


일반적으로 표준 복제는 간단한 값 부여 작업의 호출을 가리킨다. 즉, =조작부호를 사용하여 하나의 변수를 다른 변수에 부여하는 것이다. 예를 들어 다음과 같다.
int a = 5;
int b;
b = a;

그러면 b는 a의 복사본을 얻었다. b와 a의 메모리 주소는 다르고 그들은 각각 다른 메모리 구역을 차지한다.그러나 만약 당신이 이런 방식으로CoreFoundation 대상을 복제하려고 한다면 복제는 대상의 인용일 뿐이고 대상 자체는 실제 복제되지 않는다.
컨테이너 클래스 대상이든 비컨테이너 클래스 대상이든copy는 변하지 않는 대상을 되돌려주고mutablecopy는 변하지 않는 대상을 되돌려줍니다.

둘.시스템의 비컨테이너 클래스 객체


다음은 비컨테이너 클래스 객체의 복제본NSStringNSMutableString에 대해 설명합니다.
  • 불변 대상의copy
  •     NSString *str = [NSString stringWithFormat:@"123"];
        NSString *c= [str copy];// ,str:123 ,cpstr:123
        NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
        NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);
    
    2015-08-06 15:37:42.001 TableViewDemo[57923:1652639] STR:0x7fe88272d0f0 recount = 2
    2015-08-06 15:37:44.760 TableViewDemo[57923:1652639] CPstr:0x7fe88272d0f0 recount = 2
    

    str와cpstr는 같은 대상을 가리키며,copy 후 대상의 인용 계수는 2로 증가합니다
  • 불변 대상의mutableCopy
  •     NSString *str = [NSString stringWithFormat:@"123"];
        NSMutableString *cpstr = [str mutableCopy];// ,str:1 ,cpstr:15
        NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
        NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);
    
    2015-08-06 15:44:07.437 TableViewDemo[58020:1656801] STR:0x7f8610723090 recount = 1
    2015-08-06 15:44:07.437 TableViewDemo[58020:1656801] CPstr:0x7f8610721010 recount = 1
    

    str와cpstr는 서로 다른 대상을 가리키며,mutableCopy는str의 인용 계수에 영향을 주지 않습니다.
  • 가변 대상의copy
  •     NSMutableString *str = [NSMutableString stringWithFormat:@"123"];
        NSString *cpstr = [str copy];// ,str:123 ,cpstr:123
        NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
        NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);
    
    2015-08-06 15:49:27.503 TableViewDemo[58085:1661052] STR:0x7fdc62739250 recount = 1
    2015-08-06 15:49:27.504 TableViewDemo[58085:1661052] CPstr:0x7fdc62737f40 recount = 1
    

    str와cpstr는 서로 다른 대상을 가리키며,copy는str 인용 계수에 영향을 주지 않습니다.또한copy가 얻은 대상은 변할 수 없기 때문에cpstr를 변경할 수 없습니다.
  • 가변 객체의mutableCopy
  •     NSMutableString *str = [NSMutableString stringWithFormat:@"123"];
        NSMutableString *cpstr = [str mutableCopy];// ,str:123 ,cpstr:123
        NSLog(@"STR:%p recount = %ld",str,[str retainCount]);
        NSLog(@"CPstr:%p recount = %ld",cpstr,[cpstr retainCount]);
    
    2015-08-06 15:53:21.852 TableViewDemo[58152:1664413] STR:0x7fe69b6515d0 recount = 1
    2015-08-06 15:53:21.853 TableViewDemo[58152:1664413] CPstr:0x7fe69b653330 recount = 1
    

    str와cpstr는 서로 다른 대상을 가리키며,mutableCopy는str 인용 계수에 영향을 주지 않습니다.
    요약:
  • 변할 수 없는 대상의copy는retain 성질과 같이, mutableCopy는 깊이 복사, 새로운 메모리 복사입니다.
  • 가변 대상의copy,mutableCopy는 모두 깊이 복사하고 메모리의 복사입니다.주의해야 할 것은 코피가 얻은 대상은 변할 수 없다는 것이다.

  • 시스템의 컨테이너 클래스 객체


    우선, 상기 결론(즉 비용기류 대상의 복사 규칙)은 시스템 용기류 대상에 여전히 적용되지만 변화가 있다.
  • 불변 대상의copy
  • //copy ,mutablecopy 
        NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSArray *arrayCopy = [array copy];
        //arrayCopy1 array NSArray ( ), array 
        NSLog(@"arrar:%p recount: %ld",array ,[array retainCount]);
        NSLog(@"arraycopy:%p recount: %ld",arrayCopy,[arrayCopy retainCount]);
        NSLog(@"object of array[0]:%p ,retaincount:%ld",array[0],[array[0] retainCount]);
        NSLog(@"object of arrayCopy[0]:%p ,retaincount:%ld",arrayCopy[0],[arrayCopy[0] retainCount]);
    
    2015-08-06 16:30:56.088 TableViewDemo[58790:1689296] arrar:0x7fd7fbf668a0 recount: 2
    2015-08-06 16:30:56.088 TableViewDemo[58790:1689296] arraycopy:0x7fd7fbf668a0 recount: 2
    2015-08-06 16:30:56.088 TableViewDemo[58790:1689296] object of array[0]:0x7fd7fbf64a80 ,retaincount:2
    2015-08-06 16:30:56.089 TableViewDemo[58790:1689296] object of arrayCopy[0]:0x7fd7fbf64a80 ,retaincount:2
    

    용기 자체가 얕은 복사일 뿐만 아니라 용기 안의 원소도 얕은 복사이다.
  • 불변 대상의mutableCopy
  •   NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSMutableArray *mArrayCopy = [array mutableCopy];
        //mArrayCopy array , array , array1 。mArrayCopy 
        NSLog(@"arrar:%p recount: %ld",array ,[array retainCount]);
        NSLog(@"mArraycopy:%p recount: %ld",mArrayCopy,[mArrayCopy retainCount]);
        NSLog(@"object of array[0]:%p ,retaincount:%ld",array[0],[array[0] retainCount]);
        NSLog(@"object of mArrayCopy[0]:%p ,retaincount:%ld",mArrayCopy[0],[mArrayCopy[0] retainCount]);   
    
    2015-08-06 16:38:13.488 TableViewDemo[58951:1696194] arrar:0x7fd902c1cb50 recount: 1
    2015-08-06 16:38:13.497 TableViewDemo[58951:1696194] mArraycopy:0x7fd902c66e10 recount: 1
    2015-08-06 16:38:13.497 TableViewDemo[58951:1696194] object of array[0]:0x7fd902c7e400 ,retaincount:3
    2015-08-06 16:38:13.497 TableViewDemo[58951:1696194] object of mArrayCopy[0]:0x7fd902c7e400 ,retaincount:3
    

    용기 자체는 깊은 복사이지만 용기 안의 원소는 얕은 복사이다.
  • 가변 대상의copy
  •  NSMutableArray *mArray = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSArray *arrayCppy = [mArray copy];
        NSLog(@"mArray:%p recount: %ld",mArray ,[mArray retainCount]);
        NSLog(@"array:%p recount: %ld",arrayCppy,[arrayCppy retainCount]);
        NSLog(@"object of mArray[0]:%p ,retaincount:%ld",mArray[0],[mArray[0] retainCount]);
        NSLog(@"object of arrayCopy[0]:%p ,retaincount:%ld",arrayCppy[0],[arrayCppy[0] retainCount]);
    
    2015-08-06 16:48:23.686 TableViewDemo[59111:1703503] mArray:0x7fdef85076c0 recount: 1
    2015-08-06 16:48:23.687 TableViewDemo[59111:1703503] array:0x7fdef8514a10 recount: 1
    2015-08-06 16:48:23.687 TableViewDemo[59111:1703503] object of mArray[0]:0x7fdef850f300 ,retaincount:3
    2015-08-06 16:48:23.687 TableViewDemo[59111:1703503] object of arrayCopy[0]:0x7fdef850f300 ,retaincount:3
    

    용기 자체는 깊은 복사이지만 용기 안의 원소는 확실히 얕은 복사이다.
  • 가변 객체의mutableCopy
  • NSMutableArray *mArray = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSMutableArray *mMArrayCopy = [mArray mutableCopy];
        NSLog(@"mArray:%p recount: %ld",mArray ,[mArray retainCount]);
        NSLog(@"mMArrayCopy:%p recount: %ld",mMArrayCopy,[mMArrayCopy retainCount]);
        NSLog(@"object of mArray[0]:%p ,retaincount:%ld",mArray[0],[mArray[0] retainCount]);
        NSLog(@"object of mMArrayCopy[0]:%p ,retaincount:%ld",mMArrayCopy[0],[mMArrayCopy[0] retainCount]);
    
    2015-08-06 16:50:28.608 TableViewDemo[59165:1705342] mArray:0x7f8aba59b440 recount: 1
    2015-08-06 16:50:28.608 TableViewDemo[59165:1705342] mMArrayCopy:0x7f8aba59edf0 recount: 1
    2015-08-06 16:50:28.609 TableViewDemo[59165:1705342] object of mArray[0]:0x7f8aba59aff0 ,retaincount:3
    2015-08-06 16:50:28.609 TableViewDemo[59165:1705342] object of mMArrayCopy[0]:0x7f8aba59aff0 ,retaincount:3
    

    용기 자체는 깊은 복사이지만 용기 안의 원소는 얕은 복사이다.
    요약:
  • 가변 대상이든 불변 대상이든copy든mutableCopy든 용기 내 원소는 항상 얕은 복사입니다.

  • 변할 수 없는 대상의copy, 용기 자체는 얕은 복사입니다.가변 대상의copy, 용기 자체는 깊이 복사;가변 대상이든 불변 대상이든mutableCopy 용기 자체는 깊은 복사입니다.


  • 그렇다면 용기 안의 원소를 어떻게 복사합니까?

    요소의 깊이 복사

  • 방법1: 용기 자체의 깊은 복사뿐만 아니라 그 원소도 깊은 복사를 실현했지만 그 불가변한 대상은 여전히 얕은 복사이다.
  • NSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];
    

    예:
         NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSArray *deepCopyArray=[[NSArray alloc] initWithArray:array copyItems:YES];
        NSLog(@"object of array[0]:%p ,retaincount:%ld",array[1],[array[1] retainCount]);
        NSLog(@"object of deepCopyArray[0]:%p ,retaincount:%ld",deepCopyArray[1],[deepCopyArray[1] retainCount]);
        
        NSLog(@"object of array[1]:%p ,retaincount:%ld",array[1],[array[1] retainCount]);
        NSLog(@"object of deepCopyArray[1]:%p ,retaincount:%ld",deepCopyArray[1],[deepCopyArray[1] retainCount]);
    
    2017-08-18 15:46:25.560 CopyLearn[30825:19466602] array:0x61000004e490 recount: 1
    2017-08-18 15:46:25.560 CopyLearn[30825:19466602] deepCopyArray:0x61000004df80 recount: 1
    2017-08-18 15:46:25.560 CopyLearn[30825:19466602] object of array[0]:0x61000006f640 ,retaincount:2
    2017-08-18 15:46:25.562 CopyLearn[30825:19466602] object of deepCopyArray[0]:0xa000000000000611 ,retaincount:-1
    2017-08-18 15:46:25.562 CopyLearn[30825:19466602] object of array[1]:0x10dd37080 ,retaincount:-1
    2017-08-18 15:46:25.562 CopyLearn[30825:19466602] object of deepCopyArray[1]:0x10dd37080 ,retaincount:-1
    

    가변 대상에 대한copy 메시지는 깊은 복사가 가능하지만 @ "b"와 같은 상수 문자열은 본질적으로 얕은 복사입니다.
    더 나아가 array를 다음과 같이 수정합니다.
        NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@[@"b"],@"c",nil];
    

    이 때 log는 다음과 같이 표시됩니다.
    2017-08-18 15:47:52.331 CopyLearn[31018:19471465] array:0x600000245010 recount: 1
    2017-08-18 15:47:52.331 CopyLearn[31018:19471465] deepCopyArray:0x600000244d10 recount: 1
    2017-08-18 15:47:52.331 CopyLearn[31018:19471465] object of array[0]:0x600000079440 ,retaincount:2
    2017-08-18 15:47:52.331 CopyLearn[31018:19471465] object of deepCopyArray[0]:0xa000000000000611 ,retaincount:-1
    2017-08-18 15:47:52.331 CopyLearn[31018:19471465] object of array[1]:0x600000004770 ,retaincount:3
    2017-08-18 15:47:52.332 CopyLearn[31018:19471465] object of deepCopyArray[1]:0x600000004770 ,retaincount:3
    

    이때, @[@"b"]는 하나의 그룹입니다. 변경할 수 없는 그룹입니다. 이때는 여전히 얕은 복사입니다!
    그래서 이런 깊은 복사는 변할 수 없는 대상이 깊은 복사를 실현하지 못했다.
  • 방법2:
  • NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
    

    인스턴스:
     NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
        NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:array]];
        NSLog(@"array:%p recount: %ld",array ,[array retainCount]);
        NSLog(@"trueDeepCopyArray:%p recount: %ld",trueDeepCopyArray,[trueDeepCopyArray retainCount]);
        NSLog(@"object of array[0]:%p ,retaincount:%ld",array[0],[array[0] retainCount]);
        NSLog(@"object of trueDeepCopyArray[0]:%p ,retaincount:%ld",trueDeepCopyArray[0],[trueDeepCopyArray[0] retainCount]);
        NSLog(@"object of array[1]:%p ,retaincount:%ld",array[1],[array[1] retainCount]);
        NSLog(@"object of trueDeepCopyArray[1]:%p ,retaincount:%ld",trueDeepCopyArray[1],[trueDeepCopyArray[1] retainCount]);
    
    2017-08-18 15:52:21.947 CopyLearn[31140:19482635] array:0x600000242670 recount: 1
    2017-08-18 15:52:21.947 CopyLearn[31140:19482635] trueDeepCopyArray:0x600000242f10 recount: 1
    2017-08-18 15:52:21.947 CopyLearn[31140:19482635] object of array[0]:0x60000006e180 ,retaincount:2
    2017-08-18 15:52:21.948 CopyLearn[31140:19482635] object of trueDeepCopyArray[0]:0x60000006e240 ,retaincount:1
    2017-08-18 15:52:21.948 CopyLearn[31140:19482635] object of array[1]:0x10d815080 ,retaincount:-1
    2017-08-18 15:52:21.948 CopyLearn[31140:19482635] object of trueDeepCopyArray[1]:0xa000000000000621 ,retaincount:-1
    

    이때 수조 내의 모든 원소는 진정한 의미의 깊은 복사를 실현했고 상수를 포함했다.
    그렇다면 불가변의 대상도 마찬가지인지에 대한 답은 긍정적이다.
    상수의retainCount가 왜 -1인지 궁금한 게 있을지도 몰라요.길을 가리키다

    참고 자료

  • iOS 개발의 깊은 복사와 얕은 복사(mutable Copy와 Copy) 상세
  • 공식 가이드
  • 좋은 웹페이지 즐겨찾기