Swift

Class와 Struct에 대하여 간단정리 - Swift

나른한코딩 2022. 4. 12. 17:13

구조체와 클래스는 OOP를 위한 필수요소로 프로그램 코드를 추상화하기 위해 사용한다.

 

Q. 클래스/구조체로부터 A인스턴스를 생성하고,

    B인스턴스에 A인스턴스를 대입한 후 B인스턴스의 값을 변경하면?

 

  Class  

참조 타입(referenceType) 이다.

하나의 복제된 데이터를 할당한 인스턴스들이 함께 공유한다.

참조타입의 인스턴스들은 하나의 복제된 데이터를 공유한다. (즉, B인스턴스에는 A인스턴스의 참조 값이 전달된다.)

매번 새로운 인스턴스를 만들 때마다 같은 메모리 주소를 참조한다.

 

- 상속이 가능하다.

- 프로토콜 사용 가능하다.

- extension 을 할 수 있다.

- subscript 사용 가능하다.

- 타입캐스팅이 가능하다.

- Reference Count 계산에 포함된다.

 

ex) class, function, closure

→ A. A인스턴스의 원본값이 바뀌게 된다.

 

 

  Struct  

값 타입(valueType) 이다.

자신의 데이터(값)를 복제해서, 할당한 인스턴스마다 유니크하게 갖고 있는다.

값타입의 인스턴스는 각자 독립된 인스턴스이다.

자신만의 메모리를 할당하여 데이터를 가지고 있다.

 

- 상속이 불가능하다.

- 프로토콜 사용 가능하다.

 

ex) struct, enum, tuple, Array, String, Dictionary

+ 공식무서

+ Swift Standard Library의 데이터타입의 대부분이 구조채로 구현되어있다.

→ A. A인스턴스는 초기에 할당한 값 그대로있고, B만 바뀌어있다.

 

 

 

 

 

 

예제 코드

import UIKit

// Class
class Person {
  let name: String
  var age: Int
  
  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

let keen = Person(name: "keen", age: 20)
var jack = Person(name: "jack", age: 20)

// 인스턴스가 let으로 선언되어있어도 변경 가능!
keen.name = "keen2" // error : let 프로퍼티
jack.name = "jack2" // error : let 프로퍼티

keen.age = 22
jack.age = 33


// Struct
struct Car {
  let color: String
  var owner: String
}

let newCar = Car(color: "red", owner: "keen")
var oldCar = Car(color: "yellow", owner: "jack")

// 인스턴스가 let으로 선언되어있으면 변경 불가!
newCar.owner = "Hue" // error : let 인스턴스
newCar.color = "green" // error : let 프로퍼티

oldCar.owner = "Hue"
oldCar.color = "blue" // error : let 프로퍼티

// 공통: 내부 프로퍼티가 let으로 선언되어있으면 변경 불가능

 

 


 

 

두 타입은 메모리의 어디에 할당될까?

 

  Class  

Heap 영역에 저장된다.

Heap 영역에 저장된 데이터들은 모두 컴파일 타임이 아닌 런타임에 크기가 결정된다.

즉, 런타임에 추가적인 연산이 이루어 진다.

또한 한 프로세스의 스레드들이 함께 공유하는 영역이기 떄문에 Thread-Safe를 보장하지 않는다.

 

  Struct  

Stack 영역에 저장된다.

Stack 영역은 각 스레드가 독립적으로 사용하기 때문에 Thread-Safe 하다.

스택 포인터만 이동시키면 되기 떄문에 한 번의 명령으로 할당과 해제가 가능하다.

컴파일 타임에 할당할 크기가 결정되기 떄문에 메모리를 따로 관리해주지 않아도된다.

즉, 새로 데이터를 할당할 영역을 따로 계산하지 않아도된다는 뜻이다.

 

→ 위를 바탕으로 보면 Struct가 메모리 관리 측면에서 더 유리하다고 보여진다.

 

 

 

 

두개의 인스턴스를 어떻게 비교할까?

  Class  

  • === 을 통해 두 참조 타입을 비교할 수 있다.
  • (두 인스턴스의 모든 프로퍼티가 같은지 비교)

 

  Struct  

  • == 을 통해 두 값 타입을 비교할 수 있다.
  • (두 인스턴스가 같은 메모리 주소를 참조하고 있는지 비교)

 

 

 

 

 


 

 

각자 언제 사용하며 좋을까??

 

  Class  

참조타입은 하나의 데이터를 공유하기때문에 앱의 여러 곳에서 사용 시 한 영역에서 수정한 값이 다른 곳에서도 적용된다.

+ Objectice-C 에서 지원하는 API를 사용할 때는 Objectice-C 의 클래스를 상속받아서 사용해야 하기 때문에,

   이런 경우에도 클래스를 사용한다.

 

  Struct  

값타입은 항상 유니크하고 복제된 인스턴스를 가지고 있기때문에,

해당 데이터가 앱의 다른 부분에서 변경될 일이 없다.

그렇기 때문에 multi-threaded 환경에서 다른 스레드가 데이터를 바꿀 격정이 없다.

 

아래의 공식문서의 글도 참고하면 좋을것 같다.

"Choosing Between Structures and Classes"

 

 

 

 

 

 

 

 

 

 

반응형