본문 바로가기
iOS/Swift

Swift) Struct vs Class

by Jiseong 2022. 2. 12.

Struct - Value Type

구조체는 하나 이상의 프로퍼티를 묶어 새로운 타입을 정의하는 도구이다. 

 

[명명법 : 타입의 이름은 UpperCamelCase 를 사용하고, 내부 프로퍼티와 메소드는 LowerCamelCase를 사용한다.]

struct Person {
    let name: String 
    let age: Int
    
    func run() {
        // ...
    }
}

구조체의 경우는 개발자가 직접 이니셜라이저를 생성하지 않아도, 자동적으로 생성된 멤버와이즈 이니셜라이저를 통하여 인스턴스 프로퍼티의 이름으로 자동 지정된다.

struct Person {
    let name: String 
    let age: Int
    
    func run() {
        // ...
    }
}

let jiseong = Person(name: "Jiseong", age: 7) // 자동으로 지정

Swift 의 기본 자료형 타입은 모두 구조체 형태로 구현되어 있으며, 이는 Swift 기본 자료형 타입이 모두 값타입이라는 의미이다.

 

Swift에서 구조체를 인스턴스화할 때 상수에 할당하는 경우, 인스턴스 프로퍼티의 값을 변경할 수 없다.

하지만 변수에 할당할 경우, 인스턴스 프로퍼티가 변수임에 한해서 값을 변경할 수 있다

정상적으로 변경된 모습이다.

 

애플은 아래 사항에 해당한다면 Struct를 사용하라고 권장하고있다.
물론 기본 타입 또한 Struct를 쓰는 것을 권장하기도 한다.

  • 연관된 간단한 값의 집합을 캡슐화하는 것만이 목적인 경우
  • 캡슐화한 값을 참조하는 것보다 복사하는 것이 적합한 경우
  • 구조체에 저장된 프로퍼티가 값타입이며, 참조하는 것보다 복사하는 것이 적합한 경우
  • 다른 타입으로부터 상속받거나 자신을 상속할 필요가 없는 경우

위 4가지 사항을 보면.. 

상속받거나 상속할 일이 없으면 그냥 구조체써라~ 라고 느껴진다.

Class - Reference Type

클래스는 구조체와 마찬가지로 여러 프로퍼티를 담고 데이터를 용도에 맞게 캡슐화하는 용도로 사용된다. 하나의 새로운 사용자 정의 타입을 만들어주는 것이다.

 

구조체와 동일하게 명명한다. 

 

[명명법 : 타입의 이름은 UpperCamelCase 를 사용하고, 내부 프로퍼티와 메소드는 LowerCamelCase를 사용한다.]

class AnyClass {
	var name: String
	init(name: String) {
		self.name = name
	}
}

var aClass = AnyClass(name: "A")
var bClass = aClass // aClass와 bClass는 같은 인스턴스를 참조한다.

bClass.name = "B"

print(aClass.name) // B
print(bClass.name) // B

 

reference 타입은 상수에 인스턴스를 할당해도 인스턴스 프로퍼티를 수정할 수 있고, 왜 value 타입은 상수에 인스턴스를 할당하면 인스턴스 프로퍼티를 수정할 수 없는가?

 

위의 구조체와 달리 레퍼런스 타입인 클래스는 상수에 인스턴스를 할당해도 인스턴스 프로퍼티를 수정할 수 있다.

(구조체는 상수에 인스턴스를 할당하면 인스턴스 프로퍼티가 변수여도 값 수정 불가)

 

이는 레퍼런스 타입의 특성이다.

클래스의 경우 상수에 인스턴스를 할당하면 값타입처럼 인스턴스를 복사하여 할당하는 것이 아닌, 참조할 주소값을 할당하는 것이므로, 주소값을 수정할 수 없는거지, 인스턴스 프로퍼티를 수정할 수 없는 것이 아니다.

 

즉, 상수에 인스턴스를 할당해도 힙주소값을 할당한 것이기에 주소값을 찾아갔을 때 인스턴스 프로퍼티 값은 수정할 수 있는 것이다.

 

음.. 그니깐 값타입 인스턴스를 상수에 할당하면 "너 이 인스턴스 못건들여" 이고, 레퍼런스타입 인스턴스를 상수에 할당하면 "너 이 인스턴스 주소값 못건들여" 인 것이다.

Class vs Struct

공통점

  • 값을 저장하기 위해 프로퍼티를 정의할 수 있다.
  • 기능 실행을 위해 메소드를 정의할 수 있다.
  • 초기화될 때의 초기값을 지정하기 위해 이니셜라이저를 정의할 수 있다.
  • 초기 구현 및 새로운 기능 추가를 위해 익스텐션(Extension)을 통해 확 장할 수 있다.
  • 특정 기능을 실행하기 위해서 특정 프로토코을 채택할 수 있다.
    • 클래스는 상위 클래스를 상속받는 경우, 상위 클래스 뒤에 프로토콜을 채택한다.

차이점

  • 구조체는 클래스와 달리 상속 불가능
  • 타입 캐스팅은 클래스의 인스턴스에서만 사용이 가능하다
  • 디이니셜라이저(deinit)는 클래스의 인스턴스에서만 사용이 가능하다.
  • Reference Counting은 클래스의 인스턴스에만 적용된다.
    • Reference Counting이란 인스턴스를 여러 곳에서 할당하는 것을 도와준다.
    • 같은 인스턴스를 여러 곳에서 참조하고 있다는 것을 알려준다.

정리

기본적으로 Struct를 사용하는 것을 권장한다.

어디선가 원본을 수정할 필요가 있는가? - 클래스 (레퍼런스 타입)

어디선가 수정해도 원본에 영향을 주고싶지 않은가? - 구조체 (값타입)

클래스는 실체 주소로 찾아가는 Performance cost가 생긴다. - 복잡성 증가

'iOS > Swift' 카테고리의 다른 글

Swift) MVC  (0) 2022.02.12
왜 디자인 패턴을 중요시 여기는가?  (0) 2022.02.12
Swift) Notification, NotificationCenter  (0) 2022.02.12
Swift) Singleton  (0) 2022.02.12
Swift) KVO(Key-Value-Observing)  (0) 2022.02.12

댓글