에서 사용할 수있는 방법

객체 복사는 항상 코딩 패러다임에서 필수적인 부분이었습니다. 스위프트,객관적,자바 또는 다른 언어로,우리는 항상 다른 상황에서 사용하기 위해 객체를 복사해야합니다.
이 문서에서는 스위프트에서 서로 다른 데이터 형식을 복사하는 방법과 서로 다른 상황에서 동작하는 방법에 대해 자세히 설명합니다.
값 및 참조 유형
스위프트의 모든 데이터 유형은 값 유형과 참조 유형의 두 가지 범주로 크게 나뉩니다.
- 값 유형-각 인스턴스는 데이터의 고유 복사본을 유지합니다. 이 범주에 속하는 데이터 형식은—
all the basic data types, struct, enum, array, tuples
입니다. - 참조 형식 인스턴스는 데이터의 단일 복사본을 공유하며 형식은 일반적으로
class
로 정의됩니다.
두 유형의 가장 두드러진 특징은 복사 동작에 있습니다.
깊고 얕은 사본이란 무엇입니까?
값 형식이든 참조 형식이든 인스턴스는 다음 방법 중 하나로 복사할 수 있습니다.
딥 복사—모든 것을
- 딥 복사본으로 복제하면 소스가 가리키는 모든 개체가 복사되고 복사본이 대상이 가리킵니다. 따라서 두 개의 완전히 분리 된 개체가 생성됩니다.
- 컬렉션-컬렉션의 전체 복사본은 원본 컬렉션의 모든 요소가 복제된 두 개의 컬렉션입니다.
- 경쟁 조건이 적고 다중 스레드 환경에서 잘 수행되므로 한 개체의 변경은 다른 개체에 영향을 미치지 않습니다.
- 값 유형이 깊이 복사됩니다.
위의 코드,
- 줄 1:
arr1
-문자열의 배열(값 유형) - 줄 2:
arr1
이arr2
에 할당됩니다. 그러면arr1
의 딥 복사본을 만든 다음 해당 복사본을arr2
- 7~11 행에 할당합니다.
arr2
에서 수행 된 변경 사항은arr1
에 반영되지 않습니다.
이것은 딥 카피입니다—완전히 분리 된 인스턴스. 동일한 개념이 모든 값 유형과 함께 작동합니다.
일부 시나리오에서는 값 형식에 중첩 참조 형식이 포함된 경우 딥 카피가 다른 종류의 동작을 나타냅니다. 우리는 곧 섹션에서 볼 수 있습니다.
얕은 복사-가능한 한 적게 복제
- 얕은 복사본으로 원본에서 가리키는 객체도 대상에 의해 가리킵니다. 따라서 메모리에 하나의 개체 만 생성됩니다.
- 컬렉션-컬렉션의 단순 복사본은 요소가 아닌 컬렉션 구조의 복사본입니다. 얕은 복사본을 사용하면 두 컬렉션이 이제 개별 요소를 공유합니다.
- 더 빠름-참조만 복사됩니다.
- 참조 유형을 복사하면 얕은 복사본이 생성됩니다.
위의 코드,
- 1~8 행:
Address
클래스 유형 - 10 행:
a1
—Address
유형 - 11 행:
a1
가a2
에 할당됩니다. 그러면a1
의 얕은 복사본을 만든 다음 해당 복사본을a2
에 할당합니다. - 16~19 행:
a2
에서 수행 된 모든 변경 사항은a1
에 확실히 반영됩니다.

위의 그림에서a1
와a2
모두 동일한 메모리 주소를 가리킨다는 것을 알 수 있습니다.
참조 유형 깊이 복사
현재로서는 참조 유형을 복사하려고 할 때마다 개체에 대한 참조 만 복사된다는 것을 알고 있습니다. 새 개체가 생성되지 않습니다. 완전히 분리된 개체를 만들고 싶다면 어떻게 해야 할까요?
copy()
방법을 사용하여 참조 유형의 딥 복사본을 만들 수 있습니다. 문서에 따르면
복사()-copy(with:)
이 반환 한 개체를 반환합니다.
이것은NSCopying
프로토콜을 채택하는 클래스에 대한 편의 방법입니다. copy(with:)
에 대한 구현이 없으면 예외가 발생합니다.
코드 스니펫 2 에서 만든Address class
를NSCopying
프로토콜에 맞게 재구성해 보겠습니다.
위의 코드,
- 1~14 행:
Address
클래스 유형은NSCopying
를 준수하고copy(with:)
메소드 - 16 행:
a1
–Address
유형 - 17 행:
a1
는copy()
방법을 사용하여a2
에 할당됩니다. 이a1
의 깊은 복사본을 만든 다음 그 복사본을a2
에 할당합니다. - 22~25 행:
a2
에서 수행 된 변경 사항은a1
에 반영되지 않습니다.

위의 그림에서 알 수 있듯이a1
와a2
모두 서로 다른 메모리 위치를 가리 킵니다.
다른 예를 살펴 보겠습니다. 이번에는 중첩 참조 유형(다른 참조 유형이 포함 된 참조 유형)에서 어떻게 작동하는지 살펴 보겠습니다.
위의 코드,
- 줄 22:
p1
의 딥 복사본이copy()
방법을 사용하여p2
에 할당됩니다. 이것은 그들 중 하나의 변화가 다른 하나에 어떤 영향을 미치지 않아야 함을 의미합니다. - 27~28 행:
p2's
name
및city
값이 변경됩니다. 이러한p1
에 반영 하지 해야 합니다. - 30 행:
p1's
name
는 예상대로이지만city
는? >>9777 아니지? 그러나 우리는 그 일이 일어나는 것을 볼 수 없습니다."Bangalore"
은p2
에만 해당됩니까? 그래…?
딥 카피…!? 그것은 당신에게 기대되지 않았습니다. 당신은 모든 것을 복사 할 것이라고 말했다. 그리고 지금 당신은 이렇게 행동하고 있습니다. 왜 오 왜..?! 나는 무엇을 지금 하는가? 2018 년 11 월 15 일~2018 년 12 월 15 일 의 메모리 주소가 무슨 말을하는지 살펴 보자.

위의 그림에서,우리는 그것을 볼 수 있습니다
-
p1
그리고p2
은 예상대로 다른 메모리 위치를 가리 킵니다. - 그러나
address
변수는 여전히 같은 위치를 가리키고 있습니다. 즉,깊이 복사 한 후에도 참조 만 복사됩니다.
참고: 참조 형식을 복사할 때마다 깊이 복사하도록 명시적으로 지정할 때까지 기본적으로 얕은 복사본이 만들어집니다.
func copy(with zone: NSZone? = nil) -> Any{ let person = Person(self.name, self.address) return person}
Person
클래스에 대해 이전에 구현한 위의 방법에서는self.address
로 주소를 복사하여 새 인스턴스를 만들었습니다. 이렇게 하면 주소 개체에 대한 참조만 복사됩니다. 이것이p1
와p2's
address
가 모두 같은 위치를 가리키는 이유입니다.
따라서copy()
방법을 사용하여 객체를 복사하면 객체의 진정한 딥 복사본이 생성되지 않습니다.
참조 개체를 완전히 복제하려면: 모든 중첩된 참조 형식과 함께 참조 형식을copy()
메서드로 복사해야 합니다.
let person = Person(self.name, self.address.copy() as? Address)
func copy(with zone: NSZone? = nil) ->
에서 위의 코드를 사용하면 모든 방법이 작동합니다. 아래 그림에서 볼 수 있습니다.

진정한 깊은 복사-참조 및 값 유형
우리는 이미 우리가 참조 유형의 깊은 복사본을 만들 수있는 방법을 보았다. 물론 우리는 모든 중첩 참조 유형으로 그렇게 할 수 있습니다.
그러나 값 유형의 중첩 참조 유형,즉 객체 배열 또는 구조체의 참조 유형 변수 또는 튜플은 어떻습니까? 우리는copy()
도 사용하여 해결할 수 있습니까? 아니,우리는 실제로 할 수 없습니다. copy()
메서드는NSObject
하위 클래스에서만 작동하는NSCopying
프로토콜을 구현해야합니다. 값 유형은 상속을 지원하지 않으므로copy()
을 함께 사용할 수 없습니다.
2 행에서는arr1
의 구조 만 딥 복사되지만 그 안의Address
객체는 여전히 얕은 복사됩니다. 당신은 아래의 메모리 맵에서 그것을 볼 수 있습니다.

arr1
과arr2
의 요소는 모두 동일한 메모리 위치를 가리 킵니다. 이 같은 이유 때문입니다—참조 유형은 기본적으로 얕은 복사됩니다.
개체를 직렬화한 다음 직렬화를 해제하면 항상 새 개체가 만들어집니다. 값 형식과 참조 형식 모두에 유효합니다.
다음은 데이터를 직렬화하고 직렬화하는 데 사용할 수 있는 몇 가지 예입니다:
- 엔스코딩-아카이빙 및 배포를 위해 개체를 인코딩하고 디코딩할 수 있는 프로토콜입니다.
NSObject
에서 상속해야하므로class
유형 개체에서만 작동합니다. - 코드 가능-다음과 같은 외부 표현과의 호환성을 위해 데이터 유형을 인코딩하고 디코딩 할 수 있습니다. 두 값 유형—
struct, array, tuple, basic data types
및 참조 유형—class
에 대해 작동합니다.
Address
클래스를 조금 더 재구성하여Codable
프로토콜을 따르고 코드 조각 3 에서 앞부분에 추가한NSCopying
코드를 모두 제거해 보겠습니다.
위의 코드에서 11-13 행은arr1
의 진정한 딥 복사본을 만듭니다. 다음은 메모리 위치의 명확한 그림을 제공하는 그림입니다.

쓰기 시 복사
쓰기 시 복사는 값 유형을 복사할 때 성능을 향상시키는 데 도움이 되는 최적화 기술입니다.
단일 문자열 또는 지능 또는 다른 값 유형을 복사한다고 가정 해 봅시다.이 경우 중요한 성능 문제에 직면하지 않습니다. 그러나 수천 개의 요소 배열을 복사 할 때는 어떨까요? 여전히 성능 문제가 발생하지 않습니까? 복사만 하고 그 복사본만 변경하지 않으면 어떻게 될까요? 이 경우 우리가 사용한 여분의 메모리는 낭비 아닌가요?
여기에 쓰기에서 복사의 개념이 온다-복사 할 때,각 참조는 동일한 메모리 주소를 가리 킵니다. 참조 중 하나가 스위프트가 실제로 원래 인스턴스를 복사하고 수정하는 기본 데이터를 수정하는 경우에만 가능합니다.
즉,딥 복사이든 얕은 복사이든,객체 중 하나를 변경할 때까지 새 복사본이 생성되지 않습니다.
위의 코드,
- 줄 2:
arr1
의 전체 복사본이arr2
- 줄 4 및 5 에 할당됩니다.:
arr1
및arr2
여전히 동일한 메모리 주소를 가리킴 - 줄 7:
arr2
- 줄 9 및 10:
arr1
및arr2
이제 서로 다른 메모리 위치를 가리킴
이제 깊고 얕은 복사본과 데이터 유형이 다른 여러 시나리오에서 동작하는 방식에 대해 자세히 알 수 있습니다. 당신은 예제의 자신의 세트를 시도하고 당신이 얻을 어떤 결과를 볼 수 있습니다.
추가 읽기
내 다른 기사를 읽는 것을 잊지 마세요:2015 년 11 월 15 일—2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 12 월 15 일-2015 년 10