https://docs.swift.org/swift-book/documentation/the-swift-programming-language/classesandstructures
Comparing Structures and Classes
공통점
- 저장 프로퍼티 정의 가능
- 메서드 정의 가능
- subscripts 정의 가능
- 생성자로 초기 값 설정 정의
- Extension으로 기본 구현에 기능을 확장 가능
- Protocol 채택 가능
클래스가 추가적으로 갖는 것
- 하나의 클래스 상속 가능
- 타입 캐스팅으로 런타임에 클래스 인스턴스의 타입을 확인하고 해석 가능
- Deinitializer로 클래스의 인스턴스가 할당한 자원 해제 가능
- (Reference Counting) 클래스 인스턴스에 대해 하나 이상의 참조를 허용
클래스가 더 많은 기능을 제공하는 것에 대한 트레이드-오프가 존재한다.
문서에서는 구조체를 우선 사용하되, 클래스가 적절하거나 필요할 때만 사용하라고 권장하고 있다.
https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes
Choose Structures by Default
기본적으로 구조체를 선택하라. 구조체 사용은 상태 변경에 대해 안전하다.
- 구조체는 값 타입, 클래스는 참조 타입이다.
- 따라서 특정 블록 내에서 구조체의 상태가 변경되더라도 다른 부분에 영향을 미치지 않는다.
- 코드의 특정 부분에서 이뤄지는 변경 사항을 더 쉽게 추적하고 예측할 수 있다.
User Classes When You Need Objective-C Interoperability
Objective-C API가 데이터를 처리해야 하거나,
데이터 모델을 Objective-C 프레임워크에서 정의된 기존 클래스 계층에 맞춰야 한다면
데이터 모델링을 위해 클래스와 클래스 상속을 사용할 필요가 있을 수 있다.
ex. Objective-C 기반 프레임워크 UIKit
import UIKit
// UIViewController 서브클래싱
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 화면 로드 시 수행할 작업
view.backgroundColor = .white
}
}
Use Classes When You need to Control Identity
인스턴스가 Identity를 가질 필요가 있을 때 클래스를 사용하라
인스턴스가 가지는 Identity 덕분에 여러 곳에서 공유될 때 그 상태가 통일된 방식으로 유지된다.
이 특성 덕분에 파일 핸들, 네트워크 연결, 하드웨어 중개자 같은 공유 리소스를 관리할 때 적합
Identity
- 클래스에는 참조 타입이기 때문에 Identity의 개념이 존재한다.
- 두 개의 인스턴스가 모두 같은 저장 프로퍼티를 갖더라도, Identity Operator(===)로는 여전히 다른 인스턴스로 간주될 수 있음
공유된 참조
- 클래스 인스턴스는 여러 곳에서 같은 객체를 참조할 수 있다.
- 클래스 인스턴스가 앱의 여러 부분에서 공유되면, 인스턴스의 변경 사항이 참조하는 모든 곳에 영향을 준다.
- ex. 파일 핸들
- 여러 객체에서 동일한 파일에 접근할 수 있어야 하므로, 클래스를 사용하여 이러한 핸들을 공유하는 것이 적절하다.
- ex. 네트워크 연결
- 네트워크 연결은 동일한 인스턴스를 공유하면서, 연결 상태나 데이터 처리 로직이 통일되어야 한다.
- ex. 하드웨어 중개자
- CBCentralManager 같은 하드웨어 관리 객체는 여러 뷰 컨트롤러나 서비스에서 공유하면서, 동일한 상태를 유지하고 통일된 동작을 해야 한다.
- 이러한 공유 상태를 관리할 때는 접근 범위를 제한하여 코드 복잡성을 줄이는 것이 중요
Use Structures When You Don't Control Identity
Identity를 제어할 수 없는 엔티티는 구조체를 사용하라
Swift에서는 구조체가 값 타입이기 때문에, Identity를 제어하지 않거나 그 Identity가 외부 시스템에 의해 관리되는 데이터 모델을 표현할 때 유용하다.
struct PenPalRecord {
let myID: Int // 식별자, 변경 불가능한 상수
var myNickname: String
var recommendedPenPalID: Int
}
var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
- myID는 상수로 선언되어 있고, 이 값은 데이터베이스에서 Identity를 나타낸다.
- 로컬에서 이 값을 변경할 수 없으므로, 잘못된 변경을 방지할 수 있다.
- myNickname, recommendedPenPalID는 로컬에서 변경 가능하지만, 데이터베이스 수정 이전 로컬에서만 영향을 준다.
Use Structures and Protocols to Model Inheritance and Share Behavior
상속이 필요하다고 꼭 클래스를 사용해야 하는 것은 아니다.
상속 계층이 필요할 때 먼저 프로토콜 상속과 구조체를 사용하여 모델링하라
- 클래스 상속 보다 프로토콜 상속을 권장
- 프로토콜 상속은 더 유연하고, 구조체, 열거형, 클래스 모두에서 사용 가능
클래스 상속 | 프로토콜 상속 | |
타입 | 참조 타입 | 클래스, 구조체, 열거형 모두 지원 |
다중 상속 | 불가 | 다중 상속 가능 |
유연성 | 제한적 | 매우 유연 |
사용 가능 상황 | 클래스 간의 계층이 필요할 때 | 기능 중심의 상속 및 다양한 타입에서 구현할 때 |
Structures And Enumerations Are Value Types
값 타입(Value Type)
- 변수, 상수에 할당되거나 함수로 전달될 때 복사본이 생성된다.
- Swift의 정수, 부동소수점, 불린, 문자열, 배열, 딕셔너리 등의 타입은 값 타입 (내부적으로 구조체로 구현됨)
Copy-On-Write
- Collection에서는 최적화된 복사 방식을 사용한다.
- 즉시 복사되지 않고, 메모리를 공유하다가, 컬렉션 중 하나가 수정될 때 그제야 복사가 이루어지는 방식
ex.
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
Classes Are Reference Types
참조 타입(Reference Type)
- 값 타입과 달리 변수, 상수에 할당되거나 함수로 전달될 때 복사되지 않는다.
- 복사 대신, 동일한 기존 인스턴스에 대한 참조를 사용
- 여러 참조를 공유하기 때문에 값 타입보다 더 복잡하다.
- 사이드 이펙 발생 가능성
ex.
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
Pointers
- C, C++, Objective-C와 같은 다른 언어들은 메모리 주소를 참조하기 위해 포인터를 사용한다.
- Swift의 상수나 변수가 어떤 참조 타입의 인스턴스를 참조할 때, 이는 C의 포인터와 비슷하지만 메모리 주소에 대한 직접적인 포인터는 아니다.
- Swift 표준 라이브러리는 포인터와 버터 타입을 제공하며, 포인터와 직접 사용할 필요가 있을 때 사용할 수 있다.
'iOS > Swift' 카테고리의 다른 글
Swift 공식문서 8. Enumeration (0) | 2024.10.03 |
---|---|
Swift 공식문서 7. Closures (3) | 2024.09.26 |
Swift 공식문서 6. Functions (0) | 2024.09.20 |
Swift - In-Out 파라미터 (0) | 2024.09.20 |
Swift 공식문서 5. Control Flow (0) | 2024.09.19 |