Swift의 Struct와 Class
14 Feb 2017
Class와 Struct 기본 구조
Class와 Struct는 매우 유사한 데이터 타입입니다. 형태도 유사하고, 쓰임새도 비슷합니다. Swift에서도 이러한 유사성은 유지되는데요. 그렇다면 구체적으로 어떤 부분에서 차이가 있을까요? 다음의 예제를 가지고 살펴보겠습니다.
class SportsCar {
var brand: String
var model: String
}
struct Truck {
var weight: Int
var mileage: Double
}
여기서는 SportsCar
라는 Class와 Truck
이라는 구조체를 선언하였습니다. 정확히 class라는 단어와 struct라는 단어만 제외하면 그 형태가 동일합니다. 하지만, 여기서 class 부분은 컴파일 에러를 호출합니다. Swift에서는 기본적으로 class에 생성자(init)를 포함해야 하기 때문입니다.(Struct는 생성자가 없어도 됩니다.) 즉 다음과 같은 코드가 두 코드의 기본 형태입니다.
class SportsCar {
var brand: String
var model: String
init(brand: String, model: String) {
self.brand = brand
self.model = model
}
}
struct Truck {
var weight: Int
var mileage: Double
}
위와 같이 구성하면, 두 데이터 타입 모두 인스턴스(객체)를 생성할 수 있습니다.
var sportCar1 = SportsCar(brand: "포르쉐", model: "911")
var truck1 = Truck(weight: 2000, mileage: 16)
Class와 Struct의 차이
그렇다면 가장 근본적인 두 데이터 타입의 차이는 무엇일까요?
답은 바로, class는 reference type
이고, struct는 value type
이라는 점입니다.
Reference type
Value type
출처 : Reference and Value Types in Swift - Andrea Prearo
Swift 언어를 만든 Apple에서 제공하는 공식 블로그에서는 두 타입의 차이를 mutation(변하기 쉬움)의 측면에서 설명하고 있습니다. Apple blog - Value and Reference Types
위의 예제의 경우를 mutable 측면에서 살펴 보면,
var sportCar1 = SportsCar(brand: "포르쉐", model: "911")
var sportCar2 = sportCar1
sportCar2.brand = "람보르기니"
print(sportCar1.brand) // "람보르기니" 출력
var truck1 = Truck(weight: 2000, mileage: 16)
var truck2 = truck1
truck2.weight = 4000
print(truck1.weight) // 2000 출력
다음과 같이 차이가 생깁니다. 위의 경우를 살펴보면, sportCar2.brand
부분을 바꿨는데, sportCar1.brand
의 값이 변했습니다. 반면, truck2.weight
부분을 바꾼 것은 truck1.weight
에 영향을 끼치지 않았습니다. 이러한 현상이 왜 일어나는 것일까요? 그것은 reference type
과 value type
의 근본적인 메모리 모델이 다르기 때문입니다.
먼저 class의 경우, sportCar1
과 같은 변수가 SportsCar 객체의 값을 직접 저장하지 않습니다. 대신 sportCar1
변수는 sportCar1
객체의 데이터들이 저장된 장소의 주소 를 저장합니다. 그렇기 때문에, sportCar2 = sportCar1
의 결과는 sportCar2
에 sportCar1
의 주소 를 복사합니다. 반면, struct는 truck1
변수가 저장한 값을 통채로 복사하여 새로운 인스턴스를 생성하고 이를 truck1
에 할당합니다.
즉, truck2 = truck1
의 결과는 truck2
에 truck1
의 값 전체를 복사합니다. 그렇기 때문에, truck2
와 truck1
은 전혀 별개의 데이터 가 되고 둘은 서로에게 영향을 미치지 않습니다.
그렇다면 어떤 데이터를 사용해야 되나요?
많은 Swift의 API들은 class에 기반하고 있기 때문에 custom 데이터 타입을 만들 때 class를 무조건 사용해야 하는 경우가 빈번합니다. 하지만, 그 이외의 상황, 특히 multi threads 환경과 같은 곳에서는 mutable한 속성이 잘못된 결과를 쉽게 야기할 수 있기 때문에 struct를 사용할 것을 권장합니다.(기본 데이터 타입인 Array, String, Dictionary 등도 모두 value type에 속합니다.) Struct를 통해 동일한 값을 복사 하는 것은 constant time 수준만을 필요로 하고, 안전하게 데이터를 전달할 수 있습니다.
더 볼만한 추가 자료
- Apple blog - Value and Reference Types
- Reference and Value Types in Swift - Andrea Prearo
- Stackoverflow - Why Choose Struct Over Class?
참고자료 : Apple Inc. The Swift Programming Language (Swift 3.0.1)