Swift에서 데이터 유형은 값 유형(Value Types)과 참조 유형(Reference Types) 두 가지로 나뉩니다. 이 두 유형은 동작 방식에서 근본적인 차이가 있으며, 이를 이해하는 것은 Swift 프로그래밍의 핵심입니다. 프로그래밍 초보자나 다른 언어에서 Swift로 넘어온 개발자라면 이 개념이 새로울 수 있습니다. 이 글에서는 값 유형과 참조 유형의 차이점을 명확히 설명하고, 언제 어떤 유형을 사용해야 하는지 알아보겠습니다.
문서 사본을 보내기: 친구에게 문서의 복사본을 이메일로 보냅니다. 친구는 복사본을 자유롭게 편집할 수 있지만, 원본 문서는 변경되지 않습니다.
→ 이는 값 유형의 동작 방식과 유사합니다.
문서 링크를 보내기: 문서가 Google Docs나 iCloud에 저장되어 있다면, 친구에게 문서의 링크를 보낼 수 있습니다. 친구와 당신은 동일한 문서를 공유하며, 한쪽에서 변경하면 다른 쪽도 그 변경 사항을 볼 수 있습니다.
→ 이는 참조 유형의 동작 방식과 유사합니다.
문서 사본을 공유하는 것과 공유 문서의 링크를 공유하는 것의 동작 차이는 값 유형과 참조 유형 간의 동작 차이와 매우 비슷합니다.
Swift에서 구조체(structures), 열거형(enumerations), 튜플(Tuple)은 모두 값 유형입니다. 친구에게 문서 사본을 보내는 것과 비슷하게 동작합니다.
상수나 변수에 값을 할당하거나, 함수나 메서드에 값을 전달하면 항상 값의 사본이 만들어집니다.
아래 코드에서는 struct유형의 a가 Document하나의 속성으로 선언되었습니다 text.
인스턴스 Document가 생성되어 myDoc에 할당됩니다.
myDoc변수에 가 할당되면 원본 friendDoc인스턴스가 새 인스턴스로 복사됩니다.
독립적인 인스턴스이므로 text의를 변경해도 의에 friendDoc영향을 미치지 않습니다 .textmyDoc
struct Document {
var text: String
}
var myDoc = Document(text: "Great new article")
var friendDoc = myDoc
friendDoc.text = "Blah blah blah"
print(friendDoc.text) // prints "Blah blah blah"
print(myDoc.text) // prints "Great new article"
특징
독립성: 값 유형은 복사될 때마다 새로운 인스턴스가 생성되므로, 한 인스턴스의 변경이 다른 인스턴스에 영향을 미치지 않습니다.
안정성: 프로그램의 다른 부분이 값을 변경할 수 없으므로, 코드를 이해하고 디버깅하기 쉽습니다.
지역적 추론: 코드의 한 부분만 보고도 동작을 예측할 수 있습니다
Swift에서 클래스(classes), 액터(Actors), 클로저(closures)는 모두 참조 유형입니다. 이는 친구에게 공유 문서 링크를 보내는 것과 비슷하게 동작합니다.
상수나 변수에 참조 유형을 할당하거나 함수나 메서드에 전달하는 경우, 항상 할당되거나 전달되는 공유 인스턴스에 대한 참조입니다.
아래 코드는 위의 예와 동일하지만 작지만 중요한 변경 사항이 하나 있습니다. a를 선언하는 대신 이제 struct유형 Document이 a로 선언됩니다 class.
작은 코드 변경이지만, 동작에 큰 변화가 있습니다.
이전과 같이 Document인스턴스가 생성되어 할당되었습니다 myDoc.
하지만 이제 myDocfriendDoc 변수에 할당하면 할당된 인스턴스에 대한 참조가 됩니다.
이는 동일한 인스턴스에 대한 참조이므로 공유 인스턴스의 값을 포함하여 업데이트 text를 변경합니다 .friendDocmyDoc
class Document {
var text: String
}
var myDoc = Document(text: "Great new article")
var friendDoc = myDoc
friendDoc.text = "Blah blah blah"
print(friendDoc.text) // prints "Blah blah blah"
print(myDoc.text) // prints "Blah blah blah"
특징
공유 상태: 참조 유형은 동일한 인스턴스를 공유하므로, 한 곳에서 변경하면 모든 참조가 영향을 받습니다.
복잡성: 공유 가변 상태(Shared Mutable State)로 인해 코드의 다른 부분이 값을 변경할 수 있어, 디버깅이 어려울 수 있습니다.
유연성: 동일한 데이터를 여러 곳에서 공유하고 수정해야 할 때 유용합니다.
값 유형을 선택하는 경우:
데이터의 독립성이 중요할 때.
코드의 안정성과 예측 가능성이 필요할 때.
작은 데이터 구조를 다룰 때 (예: 좌표, 간단한 설정).
참조 유형을 선택하는 경우:
데이터를 공유하고 여러 곳에서 수정해야 할 때.
큰 데이터 구조를 다룰 때 (예: 네트워크 요청, 데이터베이스 연결).
상속이나 다형성이 필요한 경우.
Swift에서는 값 유형을 조합하여 더 복잡한 값 유형을 만들 수 있습니다. 예를 들어, 구조체 안에 다른 구조체, 배열, 딕셔너리 등을 포함할 수 있습니다. 모든 구성 요소가 값 유형이므로, 전체 구조체도 값 유형으로 동작합니다.
예제 코드
struct Address {
var city: String
var zipCode: String
}
struct Person {
var name: String
var address: Address
}
var home = Address(city: "Seoul", zipCode: "12345")
var person1 = Person(name: "John", address: home)
var person2 = person1 // 값 복사
person2.address.city = "Busan"
print(person1.address.city) // "Seoul" (원본은 변경되지 않음)
print(person2.address.city) // "Busan"
Swift의 배열(Array), 딕셔너리(Dictionary), 집합(Set)은 모두 값 유형입니다. 이는 다른 언어와의 중요한 차이점 중 하나입니다. 컬렉션을 복사하면 새로운 인스턴스가 생성되며, 원본과는 독립적으로 동작합니다.
값 유형: 독립적이고 안정적이며, 지역적 추론이 가능합니다. 구조체, 열거형, 튜플이 대표적입니다.
참조 유형: 공유 상태를 지원하며, 큰 데이터 구조나 상속이 필요할 때 유용합니다. 클래스, 액터, 클로저가 대표적입니다.
Swift에서는 일반적으로 구조체를 우선적으로 사용하는 것이 좋습니다. 참조 유형의 동작이 필요하지 않다면, 값 유형을 사용하여 코드의 복잡성을 줄이고 안정성을 높일 수 있습니다. 참조 유형은 공유 가변 상태가 필요한 특별한 경우에만 사용하세요.
Swift의 값 유형과 참조 유형을 이해하면, 더 안정적이고 예측 가능한 코드를 작성할 수 있습니다.
참고
https://www.swift.org/documentation/articles/value-and-reference-types.html
https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes