개발자의 삽질
[Swift] Structure vs Class 무엇을 골라야 할까? 본문
https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes
생각 없이 애플 디펠로퍼 사이트를 여기저기 돌아다니다가. 노다지 같은 글을 발견해버렸다.
그래서 바로 블로깅(번역)을 시작한다.
Choosing Between Structures and Classes
Overview
구조체와 클래스는 모두 데이터를 저장하고 앱의 동작을 모델링하기에 좋은 선택이다.
그러나 서로 비슷한 점들이 있어서 둘 중 어떤 것을 선택해야 할지 약간의 어려움이 있다.
따라서 앱에 새로운 데이터 타입을 추가할 때 다음 4가지 사항을 고려해보자
- 기본적으로 구조체를 사용하자
- Objective - C 와의 상호 호환성이 필요할 때 클래스를 사용하자
- 모델링 중인 데이터의 ID 제어가 필요할 때 클래스를 사용하자
- 구현을 공유하면서 동작을 채택할 때, 구조체와 프로토콜을 함께 사용하자.
Choose Structure by Default
일반적인 형태의 데이터를 표현할 때, 구조체를 사용하자. Swift에 있는 구조체는 다른 언어에서는 제한되어 있는 많은 기능들이 포함되어 있다: 저장 프로퍼티, 연산 프로퍼티, 그리고 메서드. 게다가 Swift는 프로토콜을 채택함으로써 기본 구현을 통해 동작을 채택할 수 있다.
구조체를 사용하게 된다면, 앱의 전체 상태를 모르더라도 코드의 한 부분을 이해하는 것이 더욱 쉬워진다. 왜냐하면, 클래스와는 다르게 구조체는 value 타입이기 때문에 구조체 내부의 로컬 변화는 고의적으로 앱에 알리는 것이 아니라면 앱의 다른 부분에서 알 수 없기 때문이다.
Use Classes When You Need Objective-C Interoperability
데이터를 처리하기 위해 Objective-C API 가 필요한 경우와 데이터 모델을 이미 Objective-C 프레임워크에 존재하는 클래스 계층과 맞춰야 할 경우에는 클래스와 클래스 상속을 이용해 데이터를 모델링해야 할 것이다. 예를 들어, 많은 Objective-C 프레임워크에서 상속받기를 원하는 클래스를 갖고 있다.
Use Classes When You Need to Control Identity
Swift 에서 클래스는 참조 타입이기 때문에 기본적으로 ID 개념을 갖고 있다. 이는 저장 프로퍼티에 같은 값을 갖고 있는 2개의 다른 클래스 인스턴스를 identity operator(===)를 통해 서로를 비교해 보았을 때, 서로 다른 인스턴스로 여겨진다. 또한, 앱에서 한 클래스 인스턴스를 공유하게 된다면, 그 인스턴스를 참조하고 있는 모든 코드들은 그 변화를 알 수 있게 된다. 이러한 identity를 원한다면 클래스를 사용하면 된다.
예를 하나 들어보자. 로컬 데이터베이스 연결에 관여하는 코드가 있다고 하자. 그 데이터베이스에 대한 접근을 관리하는 코드는 데이터베이스의 상태에 대한 완전한 제어가 필요하다. 이러한 경우에 클래스를 사용하는 것이 좋다. 그러나, 조심해야 할 점은, 앱에서 공유하는 데이터베이스 객체에 대한 접근은 적절한 제어가 필요하다.
주의할 점
이러한 Identity 를 매우 주의 깊게 다루자. 클래스 인스턴스를 앱 전체에 걸쳐 공유하는 것은 앱에 더 많은 에러를 일으킬 수 있다. 넓게 공유된 인스턴스에 변화를 주는 것에 대한 결과를 예측하기 힘들기 때문에 정확하게 코딩을 하는 것이 중요하다.
Use Structures When You Don't Control Identity
직접 제어하지 않는 ID 를 가진 엔티티 정보를 갖는 데이터를 모델링할 때 구조체를 사용하자.
원격 데이터베이스와 데이터를 주고 받는 앱을 예로 들어보자. 인스턴스의 ID는 앱에서 관리하는 것이 아니라 완전히 외부 엔티티(원격 데이터베이스)가 소유할 것이며 식별자(id)에 의해 의사소통하게 된다. 만약 앱에 담긴 모델의 일관성이 서버에 담겨 있다면, 구조체와 식별자를 이용해 레코드를 모델링할 수 있다.
아래 예시에서 서버로부터 받은 json 응답에는 PenPalRecord 로 인코딩 된 인스턴스가 있다.
struct PenPalRecord {
let myID: Int
var myNickname: String
var recommendedPenPalID: Int
}
var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
PenPalRecord 구조는 기본 데이터베이스 레코드의 ID를 제어하지 않기 때문에 로컬 PenPalRecord 인스턴스에 대한 변경 사항이 실수로 데이터베이스의 값을 변경할 위험이 없습니다
Use Structures and Protocols to Model Inheritance and Share Behavior
구조체와 클래스는 모두 상속을 지원한다. 구조체와 프로토콜은 프로토콜만 채택한다. 이 들은 클래스에서 상속할 수 없습니다. 그러나, 클래스 상속을 통해 구축할 수 있는 상속 계층의 종류는 프로토콜 상속 및 구조체를 사용하여 모델링할 수도 있습니다.
만약 상속 관계를 처음부터 구축하려고 한다면, 프로토콜 상속이 선호될 것이다. 프로토콜은 클래스, 구조체, 열거형이 상속에 참여할 수 있도록 허용하지만 클래스 상속은 다른 클래스만 호환됩니다.
'Swift' 카테고리의 다른 글
[Swift] Initialization - 2편 (Class Inheritance & Initialization) (0) | 2022.01.27 |
---|---|
[Swift] Initialization - 1편 (0) | 2022.01.24 |
[Swift] Queues & Threads - Concurrency by Tutorials 2편 (0) | 2022.01.13 |
[Swift] Inheritance (1) | 2022.01.12 |
[Swift] Enumerations 에 대해 알아보자 (0) | 2022.01.01 |