Swift에서 `class`와 `struct`는 객체 지향 프로그래밍과 값 타입을 구현하는 데 사용되는 두 가지 중요한 키워드다.
## 차이점
##### 1. **값 타입 vs 참조 타입**
- `class`: 참조 타입. 클래스 인스턴스는 힙 메모리에 저장되며, 여러 변수가 동일한 인스턴스를 참조할 수 있다. 수정 가능한 상태를 가질 수 있다.
- `struct`: 값 타입. 구조체 인스턴스는 스택에 직접 저장되거나, 힙에 저장되더라도 복사본이 전달된다. 각 변수는 독립적인 값을 가지며 수정이 다른 인스턴스에 영향을 미치지 않는다.
##### 2. **상속**
- `class`: 다중 상속을 지원하며, 부모 클래스에서 특성을 상속 받을 수 있다.
- `struct`: 상속을 지원하지 않는다.
##### 3. **참조 계수 (Reference Counting)**
- `class`: 참조 계수에 의한 메모리 관리를 사용한다. [[ARC 이해하기|ARC (Automatic Reference Counting)]]에 의해 메모리가 관리된다.
- `struct`: 참조 계수를 사용하지 않는다. 값이 복사되기 때문에 자동으로 메모리가 관리된다.
##### 4. **Initializer (생성자)**
- `class`: 초기화 메서드를 통해 객체를 초기화한다.
- `struct`: 생성자를 통해 초기화할 수 있으며, Swift는 구조체에 대한 멤버와이즈(initial memberwise) 초기화 메서드를 자동으로 제공한다.
> **멤버와이즈 초기화 메서드**
> 초기화 메서드를 별도로 생성하지 않아도 구조체의 모든 멤버 변수를 인자로 받아 간편하게 초기화할 수 있는 메서드
<br>
\+ `struct`는 한번 생성되면 **immutable하다.**
값을 바꾸려면 새로운 구조체를 생성해야 한다. mutating func을 통해 구조체의 값을 바꿀 수 있지만, 클래스처럼 프로퍼티 값만 바꿔주는 것이 아니라 아예 새로운 복사본을 생성하는 방식이다.
<br><br>
## 애플의 권장사항 ✨
#### 기본적으로는 `struct` 사용을 권장함
- Swift의 구조체는 다른 언에에서 클래스에만 허용되는 다양한 기능을 사용할 수 있음. 즉 구조체를 사용해서 간단한 데이터 모델링부터 더 복잡한 기능을 수행하는 것까지 다양한 상황에 유용하게 쓸 수 있다고 강조함
- stored properties
- computed properties
- methods
- 프로토콜 채택(코드의 재사용성과 유지보수성 고려)
- Swift 표준 라이브러리와 Foundation에서도 숫자, 문자열, 배열, 딕셔너리 데이터 타입에 구조체를 사용하고 있음
- **구조체를 사용하면 ==전체 앱의 상태를 고려하지 않고도 코드 일부분을 이해하기 쉬워짐==**
1. **구조체는 값 타입(Value Types)**
- 구조체는 값 타입이기 때문에 해당 인스턴스의 복사본이 생성되어 전달되거나 수정된다. 이는 데이터를 공유하지 않고 독립적으로 사용할 수 있다는 것을 의미한다.
2. **지역적인 변경은 외부에서 보이지 않음**
- 구조체 내부에서의 변경은 해당 구조체의 인스턴스에만 영향을 미치며, 외부에서는 해당 변경이 보이지 않는다. 이는 코드의 특정 부분에서만 발생하는 로직이 다른 부분에 미치는 영향을 최소화할 수 있게 도와준다.
3. **명시적인 통신이 필요함**
- 구조체 간의 상태 변경을 다른 부분과 공유하려면 명시적으로 통신을 해야 한다. 이는 코드의 의도를 명확히 전달하고 예기치 않은 부작용을 방지하는 데 도움이 된다.
4. **코드 섹션 별로 읽기 쉬움**
- 특정 코드 섹션을 살펴볼 때, 해당 섹션에서 일어나는 변경 사항이 명시적으로 관리되기 때문에 코드를 이해하고 디버깅하는 데 도움이 된다.
<br>
#### Objective-C 상호 운영성이 필요하면 `class`를 사용하기
- Objective-C API를 사용하거나 기존의 Objective-C 프레임워크에서 정의한 클래스 계층 구조에 데이터 모델을 적합하게 만들어야 하는 경우
→ Objective-C에서는 주로 클래스 기반의 객체 지향 프로그래밍이 사용되기 때문에 클래스를 활용해야 하는 경우가 많음
<br>
#### Identity 개념을 필요로 하는 상황에는 `class`를 사용하기
- 클래스는 참조 타입이라서 identity(식별) 개념을 가지고 있음
- 두 개의 서로 다른 클래스 인스턴스가 각각의 저장된 속성에 대해 동일한 값을 가질 때라도, 식별 연산자(\=\==)에 의해 여전히 다르게 간주된다는 것을 의미
→ 참조의 관점에서 서로 다르게 취급됨
- 클래스는 참조로 공유될 때 변경 사항이 반영됨
- 클래스 인스턴스를 여러 부분에서 참조하는 경우, 해당 인스턴스에 대한 변경 사항은 참조를 가진 코드의 모든 부분에 영향을 미침
→ 클래스를 사용하면 앱 전체에서 일관된 상태를 유지할 수 있음
- 예시 :
- 파일 다루기
- 네트워크 연결
- `CBCentralManager`와 같은 shared hardware intermediaries
- 특히 데이터베이스 연결과 같이 앱에서 중요한 상태를 관리해야 하는 경우 클래스를 사용할 수 있지만, 이 클래스에 대한 액세스를 앱의 특정 부분에만 제한해야 함
<br>
> Indentity를 다룰 때는 조심해야 한다. 클래스 인스턴스를 앱 전체에 걸쳐 광범위하게 공유하면 논리 오류가 발생할 가능성이 높아지기 때문. (많은 부분에서 인스턴스를 공유하면 해당 인스턴스를 변경하는 결과를 미리 예측하기 어려울 수 있다)
<br><br>
---
**참고 문서**
- https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes
<br>
<br>
<br>
<br>