에서 사용할 수있는 방법

객체 복사는 항상 코딩 패러다임에서 필수적인 부분이었습니다. 스위프트,객관적,자바 또는 다른 언어로,우리는 항상 다른 상황에서 사용하기 위해 객체를 복사해야합니다.

이 문서에서는 스위프트에서 서로 다른 데이터 형식을 복사하는 방법과 서로 다른 상황에서 동작하는 방법에 대해 자세히 설명합니다.

값 및 참조 유형

스위프트의 모든 데이터 유형은 값 유형과 참조 유형의 두 가지 범주로 크게 나뉩니다.

  • 값 유형-각 인스턴스는 데이터의 고유 복사본을 유지합니다. 이 범주에 속하는 데이터 형식은—all the basic data types, struct, enum, array, tuples입니다.
  • 참조 형식 인스턴스는 데이터의 단일 복사본을 공유하며 형식은 일반적으로class로 정의됩니다.

두 유형의 가장 두드러진 특징은 복사 동작에 있습니다.

깊고 얕은 사본이란 무엇입니까?

값 형식이든 참조 형식이든 인스턴스는 다음 방법 중 하나로 복사할 수 있습니다.

딥 복사—모든 것을

  • 딥 복사본으로 복제하면 소스가 가리키는 모든 개체가 복사되고 복사본이 대상이 가리킵니다. 따라서 두 개의 완전히 분리 된 개체가 생성됩니다.
  • 컬렉션-컬렉션의 전체 복사본은 원본 컬렉션의 모든 요소가 복제된 두 개의 컬렉션입니다.
  • 경쟁 조건이 적고 다중 스레드 환경에서 잘 수행되므로 한 개체의 변경은 다른 개체에 영향을 미치지 않습니다.
  • 값 유형이 깊이 복사됩니다.

위의 코드,

  • 줄 1:arr1-문자열의 배열(값 유형)
  • 줄 2:arr1arr2에 할당됩니다. 그러면arr1의 딥 복사본을 만든 다음 해당 복사본을arr2
  • 7~11 행에 할당합니다.arr2에서 수행 된 변경 사항은arr1에 반영되지 않습니다.

이것은 딥 카피입니다—완전히 분리 된 인스턴스. 동일한 개념이 모든 값 유형과 함께 작동합니다.

일부 시나리오에서는 값 형식에 중첩 참조 형식이 포함된 경우 딥 카피가 다른 종류의 동작을 나타냅니다. 우리는 곧 섹션에서 볼 수 있습니다.

얕은 복사-가능한 한 적게 복제

  • 얕은 복사본으로 원본에서 가리키는 객체도 대상에 의해 가리킵니다. 따라서 메모리에 하나의 개체 만 생성됩니다.
  • 컬렉션-컬렉션의 단순 복사본은 요소가 아닌 컬렉션 구조의 복사본입니다. 얕은 복사본을 사용하면 두 컬렉션이 이제 개별 요소를 공유합니다.
  • 더 빠름-참조만 복사됩니다.
  • 참조 유형을 복사하면 얕은 복사본이 생성됩니다.

위의 코드,

  • 1~8 행:Address클래스 유형
  • 10 행:a1Address유형
  • 11 행:a1a2에 할당됩니다. 그러면a1의 얕은 복사본을 만든 다음 해당 복사본을a2에 할당합니다.
  • 16~19 행: a2에서 수행 된 모든 변경 사항은a1에 확실히 반영됩니다.

위의 그림에서a1a2모두 동일한 메모리 주소를 가리킨다는 것을 알 수 있습니다.

참조 유형 깊이 복사

현재로서는 참조 유형을 복사하려고 할 때마다 개체에 대한 참조 만 복사된다는 것을 알고 있습니다. 새 개체가 생성되지 않습니다. 완전히 분리된 개체를 만들고 싶다면 어떻게 해야 할까요?

copy()방법을 사용하여 참조 유형의 딥 복사본을 만들 수 있습니다. 문서에 따르면

복사()-copy(with:)이 반환 한 개체를 반환합니다.

이것은NSCopying프로토콜을 채택하는 클래스에 대한 편의 방법입니다. copy(with:)에 대한 구현이 없으면 예외가 발생합니다.

코드 스니펫 2 에서 만든Address classNSCopying프로토콜에 맞게 재구성해 보겠습니다.

위의 코드,

  • 1~14 행:Address클래스 유형은NSCopying를 준수하고copy(with:)메소드
  • 16 행:a1Address유형
  • 17 행: a1copy()방법을 사용하여a2에 할당됩니다. 이a1의 깊은 복사본을 만든 다음 그 복사본을a2에 할당합니다.
  • 22~25 행:a2에서 수행 된 변경 사항은a1에 반영되지 않습니다.

위의 그림에서 알 수 있듯이a1a2모두 서로 다른 메모리 위치를 가리 킵니다.

다른 예를 살펴 보겠습니다. 이번에는 중첩 참조 유형(다른 참조 유형이 포함 된 참조 유형)에서 어떻게 작동하는지 살펴 보겠습니다.

위의 코드,

  • 줄 22:p1의 딥 복사본이copy()방법을 사용하여p2에 할당됩니다. 이것은 그들 중 하나의 변화가 다른 하나에 어떤 영향을 미치지 않아야 함을 의미합니다.
  • 27~28 행:p2'snamecity값이 변경됩니다. 이러한p1에 반영 하지 해야 합니다.
  • 30 행:p1'sname는 예상대로이지만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로 주소를 복사하여 새 인스턴스를 만들었습니다. 이렇게 하면 주소 개체에 대한 참조만 복사됩니다. 이것이p1p2'saddress가 모두 같은 위치를 가리키는 이유입니다.

따라서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객체는 여전히 얕은 복사됩니다. 당신은 아래의 메모리 맵에서 그것을 볼 수 있습니다.

arr1arr2의 요소는 모두 동일한 메모리 위치를 가리 킵니다. 이 같은 이유 때문입니다—참조 유형은 기본적으로 얕은 복사됩니다.

개체를 직렬화한 다음 직렬화를 해제하면 항상 새 개체가 만들어집니다. 값 형식과 참조 형식 모두에 유효합니다.

다음은 데이터를 직렬화하고 직렬화하는 데 사용할 수 있는 몇 가지 예입니다:

  1. 엔스코딩-아카이빙 및 배포를 위해 개체를 인코딩하고 디코딩할 수 있는 프로토콜입니다. NSObject에서 상속해야하므로class유형 개체에서만 작동합니다.
  2. 코드 가능-다음과 같은 외부 표현과의 호환성을 위해 데이터 유형을 인코딩하고 디코딩 할 수 있습니다. 두 값 유형—struct, array, tuple, basic data types및 참조 유형—class에 대해 작동합니다.

Address클래스를 조금 더 재구성하여Codable프로토콜을 따르고 코드 조각 3 에서 앞부분에 추가한NSCopying코드를 모두 제거해 보겠습니다.

위의 코드에서 11-13 행은arr1의 진정한 딥 복사본을 만듭니다. 다음은 메모리 위치의 명확한 그림을 제공하는 그림입니다.

쓰기 시 복사

쓰기 시 복사는 값 유형을 복사할 때 성능을 향상시키는 데 도움이 되는 최적화 기술입니다.

단일 문자열 또는 지능 또는 다른 값 유형을 복사한다고 가정 해 봅시다.이 경우 중요한 성능 문제에 직면하지 않습니다. 그러나 수천 개의 요소 배열을 복사 할 때는 어떨까요? 여전히 성능 문제가 발생하지 않습니까? 복사만 하고 그 복사본만 변경하지 않으면 어떻게 될까요? 이 경우 우리가 사용한 여분의 메모리는 낭비 아닌가요?

여기에 쓰기에서 복사의 개념이 온다-복사 할 때,각 참조는 동일한 메모리 주소를 가리 킵니다. 참조 중 하나가 스위프트가 실제로 원래 인스턴스를 복사하고 수정하는 기본 데이터를 수정하는 경우에만 가능합니다.

즉,딥 복사이든 얕은 복사이든,객체 중 하나를 변경할 때까지 새 복사본이 생성되지 않습니다.

위의 코드,

  • 줄 2:arr1의 전체 복사본이arr2
  • 줄 4 및 5 에 할당됩니다.: arr1arr2여전히 동일한 메모리 주소를 가리킴
  • 줄 7:arr2
  • 줄 9 및 10:arr1arr2이제 서로 다른 메모리 위치를 가리킴

이제 깊고 얕은 복사본과 데이터 유형이 다른 여러 시나리오에서 동작하는 방식에 대해 자세히 알 수 있습니다. 당신은 예제의 자신의 세트를 시도하고 당신이 얻을 어떤 결과를 볼 수 있습니다.

추가 읽기

내 다른 기사를 읽는 것을 잊지 마세요: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

  • .!!
  • 답글 남기기

    이메일 주소는 공개되지 않습니다.