Swift: Shallow Copy / Deep Copy

틀틀보·2025년 5월 19일

Swift

목록 보기
9/19

Shallow Copy (얕은 복사)

객체의 참조(주소)만을 복사하는 방식

특징

  • 참조 타입(Class 등등)에서 기본적으로 발생
  • 메모리 사용이 적고 빠름. (주소만 따라가면 되기 때문)
  • 복사된 객체와 원본 객체가 같은 인스턴스를 공유
  • 동시성 환경에서 관리 필요
class Person {
    var name: String
    init(name: String) {
        self.name = name
    }
}

let original = Person(name: "John")
let copy = original // 얕은 복사 발생
copy.name = "Jane"

print(original.name) // 출력: "Jane"

Deep Copy (깊은 복사)

객체의 모든 속성과 하위 객체들까지 재귀적으로 복사하여 독립적인 새로운 객체를 생성하는 방식

특징

  • 값 타입(Strct, Enum 등등)은 기본적으로 발생
  • 참조 타입의 경우, 수동적으로 깊은 복사 구현 필요 (NSCopying)
  • 재귀적으로 속성과 하위 객체들을 복사해야하기 때문에 메모리 사용량 ⬆️, 복사 비용 ⬆️
  • 객체 간 완전한 독립성 보장

Struct의 경우

struct Person {
    var name: String
}

var original = Person(name: "John")
var copy = original // 깊은 복사 발생

copy.name = "Jane"

print(original.name) // 출력: "John"
print(copy.name)     // 출력: "Jane"

기본적으로 깊은 복사가 진행되어 각 객체가 서로에 영향을 주지 않음!

예외) Struct 내에 참조 타입이 있는 경우

class Address {
    var city: String
    init(city: String) {
        self.city = city
    }
}

struct Person {
    var name: String
    var address: Address
}

let original = Person(name: "John", address: Address(city: "Seoul"))
var copy = original // 구조체는 깊은 복사, 하지만 address는 얕은 복사

copy.address.city = "Busan"

print(original.address.city) // 출력: "Busan"
print(copy.address.city)     // 출력: "Busan"

⚠️ 구조체 자체만 깊은 복사가 진행, 하위 참조 객체는 얕은 복사가 진행됨.

Class의 경우

class Person: NSCopying {
    var name: String
    init(name: String) {
        self.name = name
    }

    func copy(with zone: NSZone? = nil) -> Any {
        return Person(name: self.name)
    }
}

let original = Person(name: "John")
let copy = original.copy() as! Person
copy.name = "Jane"

print(original.name) // 출력: "John"

별도의 NSCopying 프로토콜을 따르는 Class를 선언하여 자신에 대한 새로운 객체를 생성해서 반환하는 copy 메서드를 선언하여 깊은 복사를 수동으로 적용

CoW (Copy-on-Write)

값 타입에서 깊은 복사가 발생할 때, 우선적으로 참조로 진행

  • 깊은 복사는 성능적으로 부담
  • 깊은 복사가 발생된 곳에서 수정이 이루어지지 않고 값을 사용만 할 경우, 성능적으로 낭비
  • 우선적으로 참조로 값을 공유하고 변경이 발생할 시에 깊은 복사를 수행
var originalArray = [1, 2, 3]
var copiedArray = originalArray // 아직 복사되지 않음

copiedArray.append(4) // 이 시점에서 실제 복사 발생

print(originalArray) // 출력: [1, 2, 3]
print(copiedArray)   // 출력: [1, 2, 3, 4]

배열에서의 복사

Swift에서의 Array

var dataArray: [String] = ["one", "two", "three"]
var dataArray2 = dataArray //깊은 복사
dataArray2.remove(at: 0)
print(dataArray)
print(dataArray2)

one, two, three, four
two, three, four

Swift 언어에서 Array는 값 타입으로 깊은 복사가 일어남. + 가변

⚠️ NSArray는 참조 타입이며 불변임.

Objective-C에서의 NSMutableArray

Objectvie-C에서의 가변 배열

var dataArray3: NSMutableArray = ["one", "two", "three"]
var dataArray4 = dataArray3 // 얕은 복사
dataArray4.remove(at: 0)
print(dataArray3)
print(dataArray4)

two, three, four
two, three, four

NSMutableArrayNSArray의 서브 클래스로 기본적으로 참조타입이며 가변이다.
참조타입이기 때문에 얕은 복사 발생

mutableCopy의 얕은 복사

새로운 배열 인스턴스를 생성하나, 배열 내 객체들은 원본과 동일한 참조를 가지게 하는 메서드

import Foundation

var dataArray5: NSMutableArray = ["one", "two", "three"]
var dataArray6 = dataArray5.mutableCopy() as! NSMutableArray
dataArray6.removeObject(at: 0)
print(dataArray5)
print(dataArray6)

one, two, three, four
two, three, four

우리가 흔히 아는 배열의 얕은 복사는 배열 자체의 주소를 똑같이 가져 원본이나 복사된 배열에서 삭제, 추가가 일어나면 그 내용이 공유되었었다.

mutable Copy를 사용하면 배열 인스턴스를 새로 생성하고 새로운 배열의 주소 공간이 배열 내 객체를 가리키기 때문에 배열에서 삭제, 추가가 이루어져도 서로 다른 공간이기 때문에 공유가 이루어지지 않음.

⚠️ 단, 공유하는 객체가 참조 타입이면 그 값 자체는 공유됨.

profile
안녕하세요! iOS 개발자입니다!

0개의 댓글