Swift에서 값 유형(구조체, 열거형, 튜플)은 value semantics를 가지고 있습니다: 전달하거나 변수에 할당할 때 모든 내용이 복사되어 독립적인 인스턴스가 생성됩니다. 이를 통해 reference 유형(클래스)에서 발생할 수 있는 shared state와 관련된 복잡성을 피할 수 있습니다.
그러나 메모리를 최적화하기 위해 컬렉션(예: 배열, 사전, 집합)은 copy-on-write 전략을 사용합니다: 복사는 인스턴스 중 하나가 변경될 때만 발생합니다.
예:
var a = [1, 2, 3] var b = a b.append(4) print(a) // [1, 2, 3] print(b) // [1, 2, 3, 4]
여기서 배열 a는 변경되지 않습니다. 비록 처음에는 공통 저장소가 있었지만, b가 변경될 때 Swift는 데이터를 개별 복사본으로 만듭니다.
중요한 점은: 구조체가 reference-type(예: 클래스)을 포함하는 경우, value semantics는 구조체 자체에만 적용되며, 내부의 참조 객체에는 적용되지 않습니다.
함수에 배열을 전달하고 함수 내에서 이를 수정하면 배열의 내용이 바뀔까요? struct와 class의 행동 차이에 대해 설명하세요.
예시와 함께 답변:
func mutate(_ arr: inout [Int]) { arr.append(100) } var source = [1, 2] mutate(&source) print(source) // [1, 2, 100]
inout으로 전달하지 않으면 함수 내에서 첫 번째 변경이 발생할 때 자동으로 복사가 이루어지며, 원본 배열은 변경되지 않습니다. 클래스의 경우 복사가 발생하지 않으며 원본 객체는 항상 변경됩니다.
이야기
개발자들이 reference 객체를 구조체 배열에 넣어 하나의 구조체에서 변경하더라도 다른 인스턴스에 영향을 미치지 않도록 기대했습니다. 실제로 한 곳에서 참조 객체를 변경하자마자 모든 곳에서 예기치 않게 변경되었습니다(shared state).
이야기
팀 프로젝트에서 race condition을 방지하기 위해 컬렉션을 매번 복사하기로 했습니다. 이로 인해 큰 배열 작업 시 메모리 낭비 및 성능 저하가 발생했습니다.
이야기
신입 개발자가 배열의 변경 사항을 추적하려고 inout으로 여러 처리 함수에 동시에 전달했습니다. 수정 순서가 불분명하게 되어 쓰레드 안전하지 않은 변경, 버그 및 동기화 오류를 초래했습니다.