Struct와 Class: Swift에서의 선택과 차이점
Swift를 공부하다 보면 Struct와 Class를 어떻게, 언제 사용해야 할지 고민되는 순간이 옵니다. 이 글에서는 두 타입의 공통점과 차이점, 그리고 상황에 따라 어떤 타입을 선택해야 할지에 대해 알아보겠습니다.
공통점
1. Struct와 Class 모두 속성(프로퍼티)과 메서드 정의 가능
struct PersonStruct {
var name: String // 속성
func greet() { // 메서드
print("Hello, \\(name)!")
}
}
class PersonClass {
var name: String = "soo" // 속성
func greet() { // 메서드
print("Hello, \\(name)!")
}
}
2. 프로토콜 준수 가능
protocol Person {
var name : String { get }
func greet()
}
struct PersonStruct : Person{
var name: String // 속성
func greet() { // 메서드
print("Hello, \\(name)!")
}
}
class PersonClass : Person{
var name: String = "soo" // 속성
func greet() { // 메서드
print("Hello, \\(name)!")
}
}
3. 확장 (extension) 사용 가능
extension PersonStruct {
func getName() -> String{
return name
}
}
extension PersonClass {
func getName() -> String{
return name
}
}
4. 초기화 메서드(init) 사용 가능
- Struct는 초기화 메서드가 정의되지 않으면 자동으로 기본 생성자를 생성해줌
struct PersonStruct {
var name: String
func greet() {
print("Hello, \(name)!")
}
}
class PersonClass {
var name: String
init(name: String) {
self.name = name
}
func greet() {
print("Hello, \(name)!")
}
}
차이점
특징 | Struct | Class |
메모리 할당 | 값 타입(Value Type) | 참조 타입(Reference Type) |
메모리 저장 위치 | 스택(Stack) | 힙(Heap) |
복사 방식 | 복사 시 독립적인 복사본 생성 (값 복사) | 복사 시 동일한 참조 공유 |
상속 가능 여부 | 상속 불가 | 상속 가능 |
deinit 지원 여부 | deinit 불가 | 소멸자(deinit) 지원 |
Mutating 키워드 | mutating 키워드를 사용해 메서드에서 속성 변경 가능 | 메서드 내에서 속성을 자유롭게 변경 가능 |
Identity | 각 인스턴스가 독립적이고 고유한 값 | 참조가 동일한 객체는 동일한 Identity를 가짐 |
1. 상속
- Struct는 상속이 불가능 하지만, Class는 상속 가능
class ParentClass {
func parent(){
print("parent")
}
}
class PersonClass : ParentClass {
var name: String
init(name: String) {
self.name = name
}
func greet() {
print("Hello, \\(name)!")
}
}
struct ParentStruct{
func parent(){
print("parent")
}
}
struct PersonStruct : ParentStruct{ // Error: Inheritance from non-protocol type 'ParentStruct'
var name: String
func greet() {
print("Hello, \\(name)!")
}
}
2. 값 타입 VS 참조 타입
- Struct는 값 타입이므로 변수나 상수에 할당될 때, 복사가 이루어지고 각각 독립적으로 존재
var struct1 = PersonStruct(name: "Alice")
var struct2 = struct1 // var struct2 = PersonStruct(name: "Alice")와 의미가 같음
struct2.name = "Bob"
print(struct1.name) // "Alice"
print(struct2.name) // "Bob"
/*
Ex)
struct1의 메모리 주소 : 0x123123
struct2의 메모리 주소 : 0x321321
*/
→ Struct는 값 타입이기 때문에 메모리에 각각의 객체가 할당됨
- Class는 참조 타입이므로 변수나 상수에 할당될 때 동일한 객체를 참조
var class1 = PersonClass(name: "Alice") // 객체의 메모리 주소를 할당
var class2 = class1 // class1에 할당된 메모리 주소 값을 받기 때문에 같은 객체를 가리킴
class2.name = "Bob"
print(class1.name) // "Bob"
print(class2.name) // "Bob"
/*
Ex)
class1의 메모리 주소 : 0x123123
class2의 메모리 주소 : 0x123123
*/
→ Class는 참조 타입이므로 변수에 할당될 때, 객체의 메모리 주소를 할당함
👉 메모리 구조
→ Person 인스턴스는 힙에 생성되며, 힙 주소가 스택에 저장됨
- 힙에 저장된 데이터를 가리키는 참조는 스택에 저장됨
힙과 스택의 차이 (Struct와 Class와의 관계 포함)
특징 | 스택(Stack) | 힙(Heap) |
저장 위치 | Struct와 같은 값 타입 | Class와 같은 참조 타입 객체 |
메모리 할당 방식 | 정적(Static) 할당 (빠름) | 동적(Dynamic) 할당 (느림) |
자체 크기 결정 | 컴파일 타임에 크기 결정 | 런 타임에 크기 결정 |
데이터 생명 주기 | 자동으로 관리 (스코프를 벗어나면 해제) | ARC 또는 수동 관리 |
복사 동작 | 값 자체를 복사 (독립적 복사본 생성) | 참조만 복사 (같은 객체를 참조) |
속도 | 빠름 | 비교적 느림 |
용량 | 작음 | 큼 |
사용 목적 | 독립적인 값 관리가 필요한 경우 | 공유나 상속이 필요한 객체 관리 |
언제 Struct를 사용하고 Class를 사용해야 할까?
Struct 사용:
- Struct 사용 권장
- 데이터가 간단하고 크기가 작을 때.
- 복사가 자주 일어나도 독립성을 유지해야 할 때.
- 값의 불변성을 보장하고자 할 때.
Class 사용:
- 참조를 공유하거나, 데이터의 상태를 여러 객체가 공동으로 관리할 때.
- 상속을 통해 계층 구조를 설계해야 할 때.
- 데이터가 더 복잡하거나 크기가 큰 경우.
'Swift' 카테고리의 다른 글
Swift - Dispatch를 이용한 성능 개선 (1) | 2024.12.09 |
---|---|
Swift - ARC (Automatic Reference Count) 정리 및 강한 순환 참조 해결 (0) | 2024.12.08 |
Swift - UICollectionViewFlowLayout 셀 크기 다르게 구현 (UILabel) (0) | 2024.12.02 |
Swift - KeyChain이란? (0) | 2024.11.24 |
Swift - modal 여러 개 한 번에 dismiss 하기 (0) | 2024.11.20 |