클래스와 구조체 (Choosing Between Structures and Classes)

Jackson·2021년 5월 3일
1

TechBlog

목록 보기
1/1

노션 버젼

참조 사이트

Choosing Between Structures and Classes

어떻게 데이터를 저장할 것이며 어떤 모델 행위를 할지 정하기.

개요

구조체클래스 모두 데이터를 저장하기 좋은 방법이고 비슷하지만, 조금은 다른 점이 있습니다.

4가지 옵션을 보고 어떤 것을 정할지 정하면 됩니다.

  • Use structures by default.
  • Use classes when you need Objective-C interoperability.
  • Use classes when you need to control the identity of the data you're modeling.
  • Use structures along with protocols to adopt behavior by sharing implementations.

풀어서 써보자면 다음과 같습니다.

  1. 일반적으로는 구조체를 쓰기
  2. Obj-C를 사용하여서 상호작용을 할 때에는 클래스를 쓰기
  3. 모델링한 identity의 데이터를 조정하기 위해 클래스 쓰기
  4. 수행을 공유하기위한 행동을 채택한 프로토콜과 함께하는 구조체를 쓰기

각각 다시 풀어서 이해를 해보겠습니다.

구조체와 클래스를 각각 만들어 보았습니다.

1. Choose Structures by Default

일반적으로는 구조체를 쓰기

  • Swift Library나 Foundation에서는 Struct를 이용해서 여러 타입들(Int,String)을 제작합니다.
  • stored property, computed property 등 다양한 기능을 제공합니다.
  • 구조체의 큰 장점은 앱 전체의 구조를 고려하지 않고 짜도 된다는 점입니다.
    • 그 이유는 value type이기에 고의적으로 바꾸지 않는이상 다른 부분에서 알 수 없습니다.
  • 따라서 구조체에 따른 특정 부분만 보면서 바꿀수 있습니다.

2. Use Classes When You Need Objective-C Interoperability

Obj-C를 사용하여서 상호작용을 할 때에는 클래스를 쓰기

  • Obj-C를 이용해서 데이터를 진행하거나 존재하는 Obj-C 프레임워크의 데이터를 조정할 때 클래스를 상속해서 써야만 합니다.
  • 많은 Obj-C 프레임워크가 사용자가 예상하는 클래스를 보여줍니다.
  • 예를들면 NS...은 모두 Obj-C 기반이며 이 때는 struct를 사용할 수 없고 class만 하위 클래스로 생성할 수 있습니다.

NSObject를 상속받을 때 구조체는 상속받지 못하네요.

3. Use Classes When You Need to Control Identity

모델링한 identity의 데이터를 조정하기 위해 클래스 쓰기

  • 클래스는 reference-type이기에 identity에 대한 개념이 있습니다.
  • 예를들면 두개의 클래스 인스턴스가 stored property에 같은 value를 가지고 있다해도 === 에 의거해서 서로 identity가 다른 점을 이해해야 합니다.

pc1과 pc2가 각각 주소가 다른임을 보여줍니다. 서로 같은 topic값을 가지고 있지만 주소가 다르기에 === 연산자에서는 다른 점을 보여주네요.
  • 다시말해 앱 전반에 하나의 클래스 인스턴스를 공유한다면 모든 자원들은 인스턴스 하나의 변화에 의해 모두 바뀌게 됩니다. 이 점을 이용하기 위해 클래스를 사용하기도 합니다.
  • 일반적인 사용처는 파일핸들, 네트워크 커넥션, CBCentralManager와 같은 곳에 쓰입니다.
  • 예를들어, local DB 연결을 표현하려할 때, DB를 연결하는 코드가 DB의 모든 상태를 앱으로부터 조종할수 있어야 합니다. 이런 상황에서 Class를 사용하고 언제 앱이 공유된 DB 오브젝트를 접근할지 한계를 정해야 합니다.
  • 주의점 : 신중하게 쓰어야 합니다. 공유하는 클래스 인스턴스는 앱 구석구석으로 퍼져 로직에러를 발생할 수 있습니다. 따라서 원치않는 결과로 인해 이 거대한 인스턴스를 수정하지 않기 위해서는, 정확하게 코드를 쓰는것이 중요합니다.

4. Use Structures When You Don't Control Identity

Identity를 조정하지 않을 때에는 구조체 쓰기

  • Identity를 컨트롤 하지 않는 엔티티 정보를 가지고 있는 데이터를 모델링 할때 구조체를 씁니다.
  • 예를 들어 remote DB를 참고할 때, 인스턴스의 identity는 외부 엔티티가 가지고 있고 id에 의해 소통이 된다고 가정합니다. 만약 서버에 앱 모델에 대한 무모순성(consistency)이 저장되었을 때, 구조체를 이용해 identity와 함께 records를 모델링 할 수 있습니다. 다음의 예제를 보면, 서버로부터 온 encoded된 PenPalRecord를 jsonResponse가 포함하고 있습니다.
struct PenPalRecord {
    let myID: Int
    var myNickname: String
    var recommendedPenPalID: Int
}

var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
  • 위와같이 로컬로서 변화는 유용합니다. 예를 들어, 앱이 사용자의 피드백에 응답하기 위해서 다양한 penpal를 추천할 것입니다. 왜냐하면 PenPalRecord 구조체는 DB에 잠재되어있는 identity를 컨트롤 하지 않기 때문입니다. 로컬에서 PenPalRecord 인스턴스를 실수로 수정한다고 하여도 어떠한 위험이 존재하지 않습니다.
  • 다른 곳에서 myNickname을 바꾸어 변화된 값을 서버에 요청한다고 해도 최근에 거절된 펜팔 추천서에는 실수로 바뀐 변화를 고르지 않을 것 입니다. 왜냐하면 myID 연산자가 상수(let)로 선언이 되었기 때문에, 로컬에서 변화할수는 없습니다. 결과적으로, db에 요청하는 것이 실수로 레코드값을 잘못 수정할 리가 없습니다.

5. Use Structures and Protocols to Model Inheritance and Share Behavior

모델을 상속하고 행동을 공유하기 위해서 구조체와 프로토콜을 사용하기

  • 구조체와 클래스 모두 상속을 지원합니다. 구조체와 프로토콜들은 오로지 프로토콜들에서 상속을 할 수 있습니다; 클래스로부터는 상속이 되지 않습니다.

구조체는 클래스를 상속할 수 없습니다.
  • 그러나 구조체와 프로토콜의 상속을 잘 이용한다면 클래스 상속과 같은 모델을 만들 수 있습니다.
  • 만약 상속관계에 대해서 처음부터 작성한다고 하면, 프로토콜 상속을 염두해두세요. 프로토콜은 클래스와 구조체, 그리고 열거형에서 상속을 가능하게 합니다, 반면에 클래스는 클래스만 상속할 수 있습니다.
  • 데이터를 어떻게 모델링할지 고를 때, 첫 번째로 프로토콜 상속을 이용해서 데이터 타입의 상속을 구축하시고, 이 프로토콜들을 구조체에 적용해 보세요.

구조체클래스의 차이 요약.

  • 이니셜라이즈 유무 : 구조체는 자동으로 init해주지만 클래스는 내부에서 꼭 init을 해주어야 합니다.
  • 값타입 vs 참조타입 구조체는 값을, 클래스는 참조를 합니다.
    • 유연성은 클래스가 좋아서 원본 접근 및 수정이 가능하고 구조체는 가능하지 않습니다.
    • 안전성은 구조체가 더 좋습니다. 로컬에서만(그것도 선언 시, var로 할 경우에만) 변경 가능할 뿐 원본 접근 수정이 불가하기 때문입니다.
    • C언어의 포인터 개념이라고 생각하시면 편하실 것 같습니다.

값을 복사하거나 구조체 자체가 상속과 거리가 있을 때, 그리고 캡슐화 목적으로는 구조체가 좋습니다.

2개의 댓글

comment-user-thumbnail
2021년 5월 3일

굿굿 b

1개의 답글