본문 바로가기

Swift/꼬꼬무

Choosing Between Structures and Classes

데이터를 저장하고 동작을 모델링 하는 방법에 대한 결정

 

앱애서 데이터를 저장하거나 모델링 하는데 구조체와 클래스는 적절하지만 둘은 유사하기 때문에 어떤것을 선택해야 할지 어렵습니다.

좋은 선택을 하기 위해 몇가지 권장 사항이 있습니다.

  • 기본적으로 구조체를 사용
  • Objective-C와 동시에 사용할때 클래스를 사용
  • 모델링 해야하는 데이터의 identity를 제어해야하는 경우 클래스를 사용 (Identity Operator)
  • 프로토콜과 함께 구조체를 사용하여 공통으로 구현된 기능을 채택하여 사용할 수 있습니다

 

Choose Strucures by Default

구조체를 사용하여 일반적인 종류의 데이터를 표현합니다. 스위프트에서 구조체는 다른 언어에서 클래스에서만 제한되는 많은 기능이 포함되어 있습니다. 구조체는 저장 프로퍼티, 계산 프로터피, 메서드를 포함할 수 있습니다.

게다가 스위프트의 구조체는 프로토콜을 채택하여 공통적인 기능을 구현할 수 있습니다.

스위프트 표준 라이브러리와 Foundation은 숫자, 문자열, 배열, 딕셔너리 같이 자주 사용하는 타입에 구조체를 사용합니다.

구조체를 사용하면 앱의 전체적인 상태를 고려할 필요 없이 코드의 부분을 추론하기 쉽습니다.

구조체는 클래스와 다르게 값 타입이기 때문에 해당 변경 사항을 앱 흐름으로 일부러 전달하지 않는 이상 로컬 변경 사항은 앱은 나머지 부분에 표시되지 않습니다.

따라서 코드 섹션을 확인하고 해당 섹션의 인스턴스에 대한 변경이 관련 함수에서 보이지 않게 수행되는 것이 아니라 명시적으로 수행될 거라는 확신을 가질 수 있습니다.

 

Use Classes When You Need Objective-C Interoperability

데이터를 처리해야하는 Objective-C API가 필요하거나 Objective-C 프레임워크에 정의된 기존 클래스의 구조에 데이터 모델을 맞춰야 하는 경우 클래스나 클래스 상속을 이용해서 데이터를 모델링해야 할 수 있습니다.

 

Use Classes When You Need to Control Identity

스위프트에서 클래스는 참조 유형이기 때문에 identity 개념이 기본적으로 제공됩니다. 즉 두개의 다른 클래스 인스턴스가 각각의 저장 프로퍼티에 같은 값을 가지고 있을때 그들은 identity operator (===)에 의해 다른 것으로 간주됩니다. 또한 앱에서 클래스 인스턴스를 공유할때 해당 인스턴스에 대한 변경이 해당 인스턴스를 참조하는 모든 코드에 표시됩니다. 인스턴스가 이런 종류의 identity를 필요로할때 클래스를 사용해야합니다.

일반적으로 사용되는 케이스는 file handles, network connections, CBCentralManager 같은 하드웨어 중개자 입니다.

예를들어 로컬 데이터베이스의 연결을 표현하는 타입의 경우, 해당 데이터베이스에 대한 액세스를 관리하는 코드는 앱에서 볼때 데이터베이스를 완전히 제어해야 합니다. 이 경우 클래스를 사용하는 것이 적절하지만 공유 데이터베이스 개체에 액세스 할 수 있는 앱의 부분을 제어해야합니다.

Important 
Identity를 신중하게 다뤄야 합니다. 클래스 인스턴스를 앱 전체에 공유하면 logic error가 발생할 가능성이 높아집니다. 많이 공유된 인스턴스를 변경할 경우 발생하는 결과를 예상하지 못할 수 있으므로, 이러한 코드를 바르게 작성하는 것이 더많은 작업이 됩니다.

 

Use Structures When You Don’t Control Identity

제어할 수 없는 ID를 가진 엔터티에 대한 정보가 포함된 데이터를 모델링할 때 구조를 사용합니다.

예를 들어 원격 데이터베이스를 참조하는 앱에서 인스턴스 ID는 외부 entity에 의해 완전히 소유되고 identity 의해 통신될 수 있습니다. 앱 모델의 일관성이 서버에 저장된 경우 레코드를 식별자가 있는 구조로 모델링 할 수 있습니다.

아래 예제에서 jsonResponse는 서버의 인코딩된 PenPalRecord 인스턴스를 포함합니다.

struct PenPalRecord {
	let myID: Int
	var myNickname: String
	var recommandedPenPanID: Int
}

var myRecord = try JSONDecoder().decode(PenPanRecord.self, from: jsonResponse)

PenPalRecord와 같은 모델 유형의 로컬 변경은 유용합니다. 예를 들어, 앱은 사용자 피드백에 대응하여 여러 개의 다른 펜팔을 권장할 수 있습니다. PenPalRecord 구조는 기본 데이터베이스 레코드의 ID를 제어하지 않으므로 로컬 PenPalRecord 인스턴스에 대한 변경 내용이 데이터베이스의 값을 실수로 변경할 위험이 없습니다.

앱의 다른 부분이 내 닉네임을 변경하고 변경 요청을 서버에 다시 제출하더라도 가장 최근에 거부된 펜팔 추천이 변경으로 인해 잘못 선택되지 않습니다. 왜냐하면 나의ID 속성이 상수로 선언되었으므로 로컬로 변경할 수 없습니다. 따라서 데이터베이스에 대한 요청이 잘못된 레코드를 실수로 변경하지 않습니다.

Use Structures and Protocols to Model Inheritance and Share Behavior

구조체와 클래스는 모두 상속 형식을 지원합니다. 구조체와 프로토콜은 프로토콜만 채택할 수 있습니다. 클래스를 상속할 수 없습니다. 그러나 클래스 상속으로 구축할 수 있는 상속 계층의 종류는 프로토콜 상속 및 구조체를 사용하여 모델링할 수도 있습니다.

처음부터 상속 관계를 구축하는 경우 프로토콜 상속을 선호합니다. 프로토콜은 클래스, 구조 및 열거형이 상속에 참여할 수 있도록 허용하지만 클래스 상속은 다른 클래스와만 호환됩니다. 데이터 모델링 방법을 선택할 때 먼저 프로토콜 상속을 사용하여 데이터 유형의 계층 구조를 구축한 다음 해당 프로토콜을 구조에 채택하십시오.

'Swift > 꼬꼬무' 카테고리의 다른 글

Methods  (0) 2023.05.23
PopLast & RemoveLast & DropLast  (0) 2023.05.22
Properties  (0) 2023.05.21
DispatchQueue with weak self  (0) 2023.05.20
Structures and Classes  (0) 2023.05.18