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 |
댓글