목차
구조체랑 클래스는 생긴건 비슷한데...
Swift에서 가장 많이 보는 Struct와 Class는 프로그래머가 데이터를 용도에 맞게 묶어 표현하고자 할 때 유용합니다.
Struct와 Class는 프로퍼티와 메서드를 사용하여 구조화된 데이터와 기능을 가질 수 있습니다다.
하나의 새로운 사용자 정의 데이터 타입을 만들어 주는 것입니다.
Struct(구조체)란?
우선 예시코드를 보겠습니다.
struct MyInformation{
var name: String
var age : Int
}
이 Struct는 문자열인 name과, 정수형인 age를 저장 프로퍼티를 가지고 있습니다.
구조체에서는 인스턴스가 생성되고 초기화된 후 프로퍼티 값에 접근하고 싶다면 '.'을 통해 접근할 수 있습니다.
만약 구조체를 상수 let으로 선언하면 인스터스 내부의 프로퍼티 값을 바꿀 수 없고 (상수이기 때문에)
변수 var로 선언하면 인스턴스 내부의 프로퍼티 값을 변경해줄 수 있습니다.
var godolInfo: MyInformation = MyInformation(name: "godol" age: 21)
godolInfo.age = 100
godolInfo.name = "david"
let davidInfo: MyInformation = MyInformation(name: "david" age: 21)
godolInfo.age = 100 // 변경 불가! 오류!
godolInfo.name = "godol" // 변경 불가!
Class(클래스)란?
Struct와 동일하게 예시 코드를 보겠습니다.
struct Person{
var height: Float = 0.0
var weight : Float = 0.0
}
이 Class는 실수형인 height와, weight 를 저장 프로퍼티를 가지고 있습니다.
클래스를 정의한 후, 인스턴스를 생성하고 초기화하고자 할 때는 기본적인 생성자(Initializer)를 사용합니다.
하지만 Person 클래스의 기본값 0.0이 지정되어있기 때문에 따로 초깃값을 전달해주지 않아도 됩니다.
구조체와 동일하게 인스턴스가 생성되고 초기화된 후 프로퍼티 값에 접근하고 싶다면 '.'을 통해 접근할 수 있습니다.
다만 차이점이 있다면 구조체와 다르게 클래스의 인스턴스는 참조 타입이므로 클래스의 인스턴스를 상수 let으로 선언해도 내부 프로퍼티 값을 변경할 수 있습니다.
var godol: Person = Person()
godol.height = 183.5
godol.weight = 78.2
let david: Person = Person()
david.height = 183.5
david.weight = 78.2
클래스 인스턴스의 소멸
클래스의 인스턴스는 참조 타입이므로 더는 참조할 필요가 없을 때 메모리에서 해제됩니다.
이 과정을 소멸이라고 하는데 소멸 직전 deinit이라는 메서드가 호출됩니다. (DeInitialized의 약어다.)
struct Person{
var height: Float = 0.0
var weight : Float = 0.0
deinit{
print("Person 클래스의 인스턴스가 소멸됩니다.")
}
}
var godol: Person = Person()
godol = nil // "Person 클래스의 인스턴스가 소멸됩니다."
구조체와 클래스의 차이
같은점
- 값을 저장하기 위해 프로퍼티를 정의할 수 있습니다.
- 기능 실행을 위해 메서드를 정의할 수 있습니다.
- 서브스크립트 문법을 통해 구조체 또는 클래스가 갖는 값(프로퍼티)에 접근하도록 서브스크립트를 정의할 수 있습니다.
- 초기화 상태를 지정하기 위해 생성자(Initializer)를 정의 할 수 있습니다.
- 초기구현과 더불어 새로운 기능 추가를 위해 Extension을 통해 확장할 수 있습니다.
- 특정 기능을 실행하기 위해 특정 프로토콜을 준수할 수 있습니다.다른점
- 구조체는 상속할 수 없습니다.
- 타입캐스팅은 클래스의 인스턴스에만 허용됩니다.
- 디이니셜라이저(DeInitializer)는 클래스의 인스턴스에만 활용 할 수 있습니다.
- 참조 횟수 계산 (Reference Counting)은 클래스의 인스턴스에만 적용 됩니다.
값 타입? 참조 타입?
구조체는 값 타입이고 클래스는 참조 타입입니다. 값 타입과 참조 타입의 가장 큰 차이는 '무엇이 전달되는가'입니다.
ex) 어떤 함수의 전달인자로 값 타입의 값을 넘긴다면 전달될 값이 복사 되어 전달 하지만 참조 타입이 전달인자로 전달될 때는 값을 복사하지 않고 참조(포인터 주소)가 전달 됩니다.
// 값 타입의 예: 구조체
struct ValueTypeExample {
var value: Int
}
func modifyValueType(valueType: ValueTypeExample) {
var modifiedValueType = valueType
modifiedValueType.value = 20
print("Inside modifyValueType: \(modifiedValueType.value)") // 20
}
var valueTypeInstance = ValueTypeExample(value: 10)
print("Before modifyValueType: \(valueTypeInstance.value)") // 10
modifyValueType(valueType: valueTypeInstance)
print("After modifyValueType: \(valueTypeInstance.value)") // 10
// 참조 타입의 예: 클래스
class ReferenceTypeExample {
var value: Int
init(value: Int) {
self.value = value
}
}
func modifyReferenceType(referenceType: ReferenceTypeExample) {
referenceType.value = 20
print("Inside modifyReferenceType: \(referenceType.value)") // 20
}
var referenceTypeInstance = ReferenceTypeExample(value: 10)
print("Before modifyReferenceType: \(referenceTypeInstance.value)") // 10
modifyReferenceType(referenceType: referenceTypeInstance)
print("After modifyReferenceType: \(referenceTypeInstance.value)") // 20
설명:
- 값 타입의 예: ValueTypeExample이라는 구조체를 정의했습니다. 구조체는 값 타입이므로 함수에 전달될 때 복사됩니다.
- 함수 modifyValueType에서 구조체의 값을 변경해도 원본 인스턴스는 변경되지 않습니다.
- valueTypeInstance는 원래 값이 10이고, 함수 호출 후에도 값이 그대로 10입니다.
- 참조 타입의 예: ReferenceTypeExample이라는 클래스를 정의했습니다. 클래스는 참조 타입이므로 함수에 전달될 때 참조(포인터 주소)가 전달됩니다. - 함수 modifyReferenceType에서 클래스의 값을 변경하면 원본 인스턴스의 값도 변경됩니다.
- referenceTypeInstance는 원래 값이 10이고, 함수 호출 후에 값이 20으로 변경됩니다.
식별 연산자
클래스의 인스턴스끼리 참조가 같은지 확인할 때는 식별 연산자(Identity Operator)를 사용합니다.
// 클래스 정의
class ExampleClass {
var value: Int
init(value: Int) {
self.value = value
}
}
// 두 개의 클래스 인스턴스 생성
let instanceA = ExampleClass(value: 10)
let instanceB = ExampleClass(value: 10)
// instanceA와 instanceB는 동일한 인스턴스가 아닙니다.
if instanceA === instanceB {
print("instanceA and instanceB refer to the same instance.")
} else {
print("instanceA and instanceB do not refer to the same instance.")
}
// instanceC는 instanceA를 참조합니다.
let instanceC = instanceA
// instanceA와 instanceC는 동일한 인스턴스입니다.
if instanceA === instanceC {
print("instanceA and instanceC refer to the same instance.")
} else {
print("instanceA and instanceC do not refer to the same instance.")
}
// instanceA와 instanceB는 다른 인스턴스를 참조하므로 식별 연산자는 false를 반환합니다.
// instanceA와 instanceC는 동일한 인스턴스를 참조하므로 식별 연산자는 true를 반환합니다.
결론
Struct(구조체)와 Class(클래스)는 Swift에서 프로그래머가 데이터를 효과적으로 관리하고 기능을 구현하는 데 매우 유용한 도구입니다. 이 두 가지는 유사한 기능을 제공하지만, 중요한 차이점들이 있습니다.
- 구조체는 값 타입으로, 주로 간단한 데이터 구조를 표현하는 데 사용됩니다. 함수에 전달될 때 복사되어 전달되므로 안전한 데이터 관리가 가능합니다. 상수로 선언된 구조체 인스턴스는 내부 프로퍼티 값을 변경할 수 없습니다.
- 클래스는 참조 타입으로, 복잡한 데이터 구조와 상속 관계를 표현하는 데 사용됩니다. 함수에 전달될 때 참조(포인터 주소)가 전달되므로 동일한 인스턴스를 여러 곳에서 공유할 수 있습니다. 상수로 선언된 클래스 인스턴스도 내부 프로퍼티 값을 변경할 수 있습니다.
또한, 클래스는 상속, 타입캐스팅, 디이니셜라이저, 참조 횟수 계산 등 고급 기능을 지원합니다. 이러한 차이점들을 이해하고 상황에 맞게 적절히 활용하는 것이 중요합니다.
요약
- 같은 점: 프로퍼티 정의, 메서드 정의, 서브스크립트 문법, 생성자 정의, 확장(Extension), 프로토콜 준수 가능.
- 다른 점: 구조체는 상속 불가, 타입캐스팅 불가, 디이니셜라이저 사용 불가, 참조 횟수 계산 불가.
- 값 타입과 참조 타입: 구조체는 값 타입으로 복사되어 전달, 클래스는 참조 타입으로 주소가 전달.
- 식별 연산자: 클래스 인스턴스끼리 참조가 같은지 확인.
이러한 이해를 바탕으로 Struct와 Class를 적절히 활용하면 Swift 프로그래밍에서 더 효율적이고 안전한 코드를 작성할 수 있습니다.
출처: 야곰, ⌜스위프트 프로그래밍 3판⌟, 한빛미디어
'iOS' 카테고리의 다른 글
[Swift] 프로퍼티 (0) | 2024.06.17 |
---|---|
[SwiftUI] SwiftUI에서 탭바 숨기기 및 커스텀 백 버튼 만들기 (0) | 2024.06.13 |
[SwiftUI] SwiftData로 로컬에 관계형 데이터 만들어보기 (0) | 2023.12.20 |
[SwiftUI] 데이터 흐름: @Binding vs 단순 변수,상수 (0) | 2023.12.19 |
[Swift] 권한 요청 사용 + 구현하기 (feat. SwiftUI) (0) | 2023.12.01 |