값 타입과 참조 타입
값 타입(Value Type) | 참조 타입(Reference Type) |
구조체, 열거형, 튜플 | 클래스, 클로저 |
값 타입
- 구조체, 열거형, 튜플 타입 자체는 데이터 메모리 영역 에서 생성된다
- 스택 메모리 영역 에 인스턴스가 생성된다
인스턴스 복사시)
- 새로운 값이 할당되어 스택 메모리 영역에 쌓인다
- 그러므로 복사본의 내부 프로퍼티를 변경하면 그 복사본의 값이 변하고 원본 값은 변하지 않는다
인스턴스 let으로 선언시)
- 인스턴스의 내부 프로퍼티들이 var로 선언되었더라도 그 값을 변경할 수 없게된다
참조 타입
- 클래스나 클로저 타입 자체도 값 타입과 마찬가지로 데이터 메모리 영역 에서 생성된다
- 힙 메모리 영역 에 생성된 인스턴스의 데이터를 저장한다
- 스택 메모리 영역 에서는 힙 메모리 영역 에 있는 인스턴스의 데이터의 메모리 주소를 저장한다
인스턴스 복사시)
- 스택 메모리 영역에 새로운 데이터가 생겨서 원본 데이터와 같은 메모리 주소를 가리킨다
- 그러므로 복사본의 내부 프로퍼티를 변경하면 가리키고 있는 메모리 주소의 데이터가 변경된다 (부수 효과 발생)
인스턴스 let으로 선언시)
- 인스턴스를 let으로 선언하면 그 인스턴스가 가르키고 있는 메모리 주소를 변경할 수 없게 된다
swift에서는 값 타입이 훨씬 더 강력한 기능을 한다
Stack의 장단점
- Stack은 Push, Pop을 통해 메모리를 할당/해제한다. → 스택 포인터만 움직이면 되므로 한번의 명령으로 메모리 할당과 해제 수행
- 선형적인 데이터 구조다. 단순하고 효율적이다.
하지만 컴파일 타임에 스택에 필요한 메모리 크기를 미리 알 수 있어야 한다.
하나의 스택이 올라갔을 때 그 크기를 확정할 수 있어야, 다음 스택이 생길 때 할당할 메모리를 알 수 있다.
또 스택이 끝나면 해제되어 버린다. 데이터를 스택에 할당하면 다른 객체에서 데이터에 접근하기가 어렵다.
Heap의 장단점
- Heap은 임의의 메모리 주소에 메모리를 할당/해제한다.
- 동적할당에 사용된다
- 메모리 할당을 할 때 순차적인 탐색이 필요하다.
- 더 이상 사용하지 않는 데이터를 탐지하기 위해 참조 카운팅(Reference counting)을 해야 한다.
- Stack보다 할당/해제에 드는 오버헤드가 크다.
다만 Heap은 런타임에 메모리 할당 크기가 변할 수 있고, 여러 객체나 스코프에서 참조값을 통해 데이터에 접근이 가능하다.
우리는 주로 값 타입은 Stack을 쓰고, 참조 타입은 Heap을 쓴다고 배운다. 그렇지 않은 경우도 있다.
즉, 시멘틱의 관점에서는 '불변성'을 가지면서도, 실제 메모리는 힙을 사용할 수도 있다는 뜻이다.
Struct vs Class 언제 무엇을 이용할까
- 최대한 구조체 사용
- 값 타입은 부수 효과가 없고 또 다른 메모리의 주소를 참조하고 있지 않으므로 특정 부분의 코드만 보고도 이해가 가능하고, 결과를 예측할 수 있다
- 멀티 스레드 환경에서 공유 데이터를 가지지 않아 안전하고 간단하다
- 스택 사용으로 인해 메모리 자원의 할당 및 해제의 성능이 효율적이다!
- 구조체도 프로토콜과 값 타입의 조합을 통해 다형성을 만들어 낼 수 있으므로 상속이 필요 없다! (swift는 Protocol-oriented)
- Cocoa framework의 타입 계층, 및 obj-c 런타임이 필요할 경우 클래스 사용
- UIKit를 서브클래싱할 경우 class 사용.
- 고유성을 가진 데이터를 제어할 경우→ 클래스 사용
- 데이터의 변화를 감지하기 위해서는 데이터의 고유성이 필요하다 ( 그 데이터의 식별할 수 있는 고유한 형태가 있어야 변경됨을 감지할 수 있다)
- 또한 앱의 여러 곳에서 사용할 때 한 영역에서 적용한 수정이 다른 영역에도 적용되기를 원하면 클래스를 사용한다
- 주로 파일 관리나 네트워크 연결과 같은 작업을 다룰 때 클래스를 사용한다
- 많은 양의 복사→ 구조체 내에 클래스 사용
- 값 타입(구조체)내에 데이터가 굉장히 많거나 복사가 많이 일어날 경우, 내부에 클래스를 활용한다 (구조체 내에 참조 타입으로 별도의 저장소 생성)
- 복사를 최소화하여 성능을 최적화한다
- 구조체가 여러번 복사되고 할당되더라도 참조 타입 내의 데이터는 값이 복사되지 않고 참조만 늘어나기 때문에 효율적으로 사용 가능하다!
- Copy-on-Write를 사용하여 변경이 일어날 경우에만 복사해준다
- 하지만 구조체 내에 참조 타입도 가급적 숫자를 줄이면 좋다 !
+) SwiftUI에서 ObservableObject 프로토콜을 채택은 class만 가능하다!!
참고
https://velog.io/@eddy_song/value-reference-decision
https://velog.io/@eddy_song/value-reference-decision#간단-설명-값-타입과-참조-타입의-차이
'Swift' 카테고리의 다른 글
[Swift] 타입 캐스팅 (0) | 2023.05.05 |
---|---|
[Swift] 프로퍼티 (0) | 2023.05.05 |
[Swift] 함수 (0) | 2023.05.01 |
[Swift] 클래스와 구조체 (0) | 2023.05.01 |
[Swift] Time Complexity (0) | 2023.04.30 |