swift

struct, class, enum

motosw3600 2021. 12. 14. 12:55

struct

  • 여러개를 한번에 묶어 추상화 하는데 사용
  • call by value(값에 의한 호출) 
  • 복사의 개념(할당할 때 새로운 객체를 생성하고 변경이 일어났을때 복사)
  • 상속 불가
  • Stack영역에 할당됨
struct B{
    var num: Int = 0
}

var test3 = B()
var test4 = test3

test3.num = 199
print(test4.num) // test4는 test3과는 별도의 메모리에 관리되고 있으므로 test4.num은 0

class

  • call by reference(참조에 의한 호출)
  • 참조의 개념(할당을 할 때 메모리를 새로 할당하는 것이 아닌 메모리를 참조)
  • 상속 가능
  • Heap영역에 할당됨
class A{
    var num: Int = 0
}

var test1 = A()
var test2 = test1

test1.num = 1

print(test2.num) // // test2도 test1을 참조하고 있기 때문에 test2의 num 값도 1

struct와 class의 공통점과 차이점

공통점

  • 프로퍼티와 메서드 정의 가능
  • subscript를 정의해 프로퍼티에 접근 가능
  • extension을 통한 확장 가능
  • 프로토콜 채택 가능

차이점

  • 구조체는 상속불가
  • 타입캐스팅은 클래스의 인스턴스만 가능
  • 디이니셜라이저(deinit)은 클래스의 인스턴스만 가능
  • RC(Reference Count)는 클래스의 인스턴스만 적용

enum

  • 그룹에 대한 연관된 값을 정의하고 사용하는것이 가능한 타입
  • 세부타입을 정의한 rawValue를 사용하여 원시값 확인 가능(원시값은 String, Number, Character타입 할당 가능)
  • switch문과 같이 사용하여 가독성을 높이고 실수를 줄인다.
  • 각 case는 비트단위의 고유값을 가지기 때문에 비교가 빠르다.
  • 너무 많이 사용하면 수정됬을 시 매번 다시 컴파일 하기 때문에 주의!
enum Fruit: String, CaseIterable {
	case apple, banana, watermelon, orange
}

let iterableList = Fruit.allCases.map { "\($0.rawValue)" }

// iterableList: ["apple", "banana", "watermelon", "orange"]

 


언제 struct또는 class를 사용해야 할까?

Apple에서 데이터나 모델을 struct, class중 결정하는 방법에대해 적은글이 있어 소개해본다. 

 

1. struct를 default로 일단 사용해라

일반적인 data를 나타낼땐 struct를 사용하는게 좋다. Swift의 sturcture는 다른언어에서 제약된 많은 특징등을 포함하고 있다.
(stored properties, computed properties, method..) 더욱이 protocol을 adopt해서 사용도 가능하다. Swift Standard Library 및 Foundation에서 제공하는 Number, String, Array, Dictionary등의 많은 타입들이 structure로 이루어져 있다. 

 

2. Objective-C 상호운용성이 필요할때 class를 사용해라

만약 당신이 Objective-C API를 사용하거나 너의 데이터를 Objective-C framework에 정의된 기존 클래스 구조에 맞춰야 할때 class를 사용해야 한다. 예를들어 많은 Objective-C framework들이 데이터 저장을 위한 subclass의 목적으로 class를 제공한다. 

 

3. 직접 identity를 제어해줘야 할 땐 class를 사용해라

class는 참조타입이기 때문에 identity의 개념을 가지고 있다. 이의미는 서로다른 클래스가 같은 프로퍼티를 가지고 있어도 identity Operator(===)를 통해 식별이 가능하다. 이것을 또한 앱내에서 인스턴스를 공유하고 있을 때 인스턴스를 변경하면 다른 참조하고 있는 모든 곳에도 변경된다는 것을 의미한다. 보통 file handle, network connection, hardware intermeiaries등에서 사용하고 있다.
※ 중요!!
identity를 다루는건 조심해야한다. class의 인스턴스를 광범위하게 공유하는것은 로직의 에러를 만들 수 있다. 너는 아마 큰 shared 인스턴스의 변경 결과를 예상할 수는 없기 때문에 더 조심스럽게 다뤄야 한다.

 

4. 직접 identity를 제어할 필요가 없으면 struct를 사용해라

Modeling중인 Data가 담고있는 정보의 Identity를 직접 제어할 필요가 없으면 structure를 사용하면 된다.
예를들어 remote database를 사용하고 있을때 인스턴스의 identity는 외부 entity에 종속되어 있다. 만약 app의 model의 일관성이 server에 저장되어 있으면, model을 identifier로 이뤄진 structure에 저장하기만 하면 된다.
아래는 서버로부터 encoding된 PenPalRecord를 포함하는 json응답객체이다.
struct PenPalRecord {
    let myID: Int
    var myNickname: String
    var recommendedPenPalID: Int
}

var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
Local에서 PenPalRecord인스턴스를 변경하는건 문제없다. 예를들어 사용자의 피드백으로 인한 여러개의 펜팔을 보여주는 경우가 있을 수 있다. 이때 PenPalRecord structure는 실제 database의 내용을 제어할 수 없기 때문에 이 구조체를 바꿔도 실제 DB의 내용이 바뀔위험은 없다.

 

5. model의 상속이나 share할때는 struct와 protocol을 사용해라

struct와 class모두 상속을 지원한다. structure + protocol로 class의 상속과 비슷하게 사용할 수 있다.
개발 초기에 상속관계를 설계한다면 protocol을 추천한다. protocol은 class, struct, enumeration이 허용되지만 class는 class끼리만 상속이 가능하다. protocol을 통해 먼저 데이터 구조를 설계하고 해당 protocol을 structure에 채택해라

 

출처 : https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes

'swift' 카테고리의 다른 글

Image Optimizing  (0) 2022.01.18
ImageCache  (0) 2022.01.18
URLSession  (0) 2021.12.10
Method Swizzling  (0) 2021.12.10
Layout Update Method  (0) 2021.12.09