[objective-c] NSArray 딥 복사

딥 복사를 허용하는 내장 기능이 NSMutableArray있습니까?

나는 주위를 둘러 보았고 어떤 사람들은 [aMutableArray copyWithZone:nil]작품을 딥 카피 라고 말합니다 . 그러나 나는 시도했고 그것은 얕은 사본 인 것 같습니다.

지금은 for루프를 사용하여 수동으로 복사하고 있습니다 .

//deep copy a 9*9 mutable array to a passed-in reference array

-deepMuCopy : (NSMutableArray*) array
    toNewArray : (NSMutableArray*) arrayNew {

    [arrayNew removeAllObjects];//ensure it's clean

    for (int y = 0; y<9; y++) {
        [arrayNew addObject:[NSMutableArray new]];
        for (int x = 0; x<9; x++) {
            [[arrayNew objectAtIndex:y] addObject:[NSMutableArray new]];

            NSMutableArray *aDomain = [[array objectAtIndex:y] objectAtIndex:x];
            for (int i = 0; i<[aDomain count]; i++) {

                //copy object by object
                NSNumber* n = [NSNumber numberWithInt:[[aDomain objectAtIndex:i] intValue]];
                [[[arrayNew objectAtIndex:y] objectAtIndex:x] addObject:n];
            }
        }
    }
}

하지만 더 깨끗하고 간결한 솔루션을 원합니다.



답변

딥 카피에 대한 Apple 문서 에는 다음과 같이 명시되어 있습니다.

1 레벨 전체 사본 만 필요한 경우 :

NSMutableArray *newArray = [[NSMutableArray alloc]
                             initWithArray:oldArray copyItems:YES];

위의 코드는 멤버가 이전 배열 멤버의 얕은 복사 본인 새 배열을 만듭니다.

전체 중첩 데이터 구조 (링크 된 Apple 문서에서 진정한 딥 카피 라고 부르는)를 깊게 복사해야하는 경우이 접근 방식으로는 충분하지 않습니다. 여기에서 다른 답변을 참조하십시오.


답변

이 작업을 쉽게 수행 할 수있는 유일한 방법은 어레이를 아카이브 한 다음 즉시 아카이브를 해제하는 것입니다. 약간의 해킹처럼 느껴지지만 실제로는 컬렉션 복사 에 대한 Apple 문서에 명시 적으로 제안되어 있습니다.

배열 배열이있는 경우와 같이 진정한 딥 카피가 필요한 경우 콘텐츠가 모두 NSCoding 프로토콜을 준수하는 경우 컬렉션을 보관 한 다음 보관 취소 할 수 있습니다. 이 기술의 예가 목록 3에 나와 있습니다.

Listing 3 진정한 딥 카피

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
          [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

문제는 객체가 NSCoding 인터페이스를 지원해야한다는 것입니다. 이는 데이터를 저장 /로드하는 데 사용되기 때문입니다.

Swift 2 버전 :

let trueDeepCopyArray = NSKeyedUnarchiver.unarchiveObjectWithData(
    NSKeyedArchiver.archivedDataWithRootObject(oldArray))


답변

기본적으로 복사는 얕은 사본을 제공합니다.

호출 copycopyWithZone:NULL기본 영역으로 복사라고도 하는 것과 동일 하기 때문 입니다. copy호출 딥 카피 발생하지 않습니다. 대부분의 경우 얕은 사본을 제공하지만 어쨌든 클래스에 따라 다릅니다. 철저한 토론 을 위해 Apple Developer 사이트 의 Collections Programming Topics 를 추천합니다 .

initWithArray : CopyItems : 1 단계 전체 복사를 제공합니다.

NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];

NSCoding 딥 카피를 제공하기 위해 Apple에서 권장하는 방법입니다.

진정한 딥 카피 (Array of Arrays)의 NSCoding경우 객체를 필요로 하고 아카이브 / 아카이브 해제합니다.

NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];


답변

Dictonary 용

NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);

어레 이용

NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);


답변

아니요,이를 위해 프레임 워크에 내장 된 것이 없습니다. Cocoa 컬렉션은 얕은 복사본 ( copy또는 arrayWithArray:메서드 사용)을 지원하지만 전체 복사 개념에 대해서는 언급하지 않습니다.

컬렉션의 내용이 사용자 지정 개체를 포함하기 시작하면 “깊은 복사”를 정의하기가 어려워지기 때문입니다. “딥 카피는”뜻 모든 객체 그래프의 객체에 대한 고유 참조 기준으로 모든 원래의 객체 그래프의 객체?

가상의 NSDeepCopying프로토콜 이 있다면이를 설정하고 모든 객체에서 결정을 내릴 수 있지만 불행히도 그렇지 않습니다. 그래프에서 대부분의 개체를 제어했다면이 프로토콜을 직접 만들어 구현할 수 있지만 필요에 따라 Foundation 클래스에 범주를 추가해야합니다.

@AndrewGrant의 대답은 keyed archiving / unarchiving의 사용을 제안하는 것은 성능이 좋지 않지만 임의의 객체에 대해 이것을 달성하는 정확하고 깨끗한 방법입니다. 이 책은 지금까지 진행되었으므로 딥 카피를 지원하기 위해 정확히 해당하는 모든 객체에 범주를 추가하는 것이 좋습니다 .


답변

JSON 호환 데이터에 대한 깊은 복사를 시도하는 경우 해결 방법이 있습니다.

간단히 JSON 개체 NSDataNSArray사용한 NSJSONSerialization다음 다시 생성하면 NSArray/NSDictionary새 메모리 참조를 사용하여 완전히 새롭고 새로운 복사본이 생성 됩니다.

그러나 NSArray / NSDictionary의 객체와 그 자식은 JSON 직렬화 가능해야합니다.

NSData *aDataOfSource = [NSJSONSerialization dataWithJSONObject:oldCopy options:NSJSONWritingPrettyPrinted error:nil];
NSDictionary *aDictNewCopy = [NSJSONSerialization JSONObjectWithData:aDataOfSource options:NSJSONReadingMutableLeaves error:nil];


답변