Swift에서는 데이터를 저장하고 조작할 때 Class(클래스)와 Struct(구조체)를 사용할 수 있다. 둘은 비슷하면서도 중요한 차이점을 가지고 있기에, 코드의 가독성과 성능을 위해 잘 선택해서 사용해야 한다. 이번 글에서는 Class와 Struct의 차이점과 각각을 언제 사용해야 하는지를 정리해본다.
Class와 Struct의 주요 차이점
특성 | Class | Struct |
메모리 할당 | Heap (참조 타입) | Stack (값 타입) |
복사 방식 | 참조 복사 (Reference) | 값 복사 (Copy) |
상속 | 가능 | 불가능 |
mutating 키워드 | 불필요 | 필요 |
참조 카운팅 (ARC) | 사용함 | 사용하지 않음 |
Equatable 자동 구현 | 직접 구현 | 가능 |
가장 큰 차이점은 class
는 참조 타입(Reference Type)이고, struct
는 값 타입(Value Type)이라는 것이다.
Class와 Struct의 동작 방식
Class
person1과 person2가 같은 인스턴스를 참조하므로, 하나를 변경하면 다른 하나도 영향을 받는다.
class Person {
var name: String
init(name: String) { self.name = name }
}
var person1 = Person(name: "춘장")
var person2 = person1
person2.name = "메주"
print(person1.name) // "메주"
print(person2.name) // "메주"
Struct
값이 복사되므로 person1과 person2는 서로 영향을 주지 않는다.
struct Person {
var name: String
}
var person1 = Person(name: "춘장")
var person2 = person1
person2.name = "감태"
print(person1.name) // "춘장"
print(person2.name) // "감태"
Class? Struct? 언제 사용할까?
Class
객체 간 데이터 공유가 필요할 때
여러 객체가 같은 데이터를 공유하고 변경해야 하는 경우
예를 들어, 네트워크 요청을 처리하는
URLSession
인스턴스나, 앱의 전역 설정을 관리하는UserDefaults
객체처럼 여러 부분에서 동일한 상태를 유지해야 할 때
상속이 필요할 때
Class는 Struct와 달리 상속이 가능하므로, 공통된 기능을 가진 객체들을 계층적으로 설계할 수 있음
예를 들어, UIKit의
UIView
,UIViewController
는 공통적인 속성과 메서드를 공유하는 상속 구조를 가짐
Identity(고유성)가 중요한 경우
값이 같더라도 동일한 객체인지 구분해야 하는 경우
예를 들어, 앱 내에서 사용자의 로그인 세션을 관리할 때, 같은 사용자 정보라도 서로 다른 인스턴스로 존재할 필요 없이 하나의 객체로 공유되어야 함
ARC(자동 메모리 관리)가 필요한 경우
객체의 라이프사이클을 관리할 때 (네트워크 세션, 데이터 관리 객체 등)
Class는 자동 참조 카운팅(ARC)을 통해 객체가 더 이상 필요하지 않을 때 메모리를 자동 해제함
여러 개의 인스턴스를 참조해야 하는 경우
같은 객체를 여러 곳에서 참조해야 할 때 Class가 유리함
예를 들어, 싱글톤 패턴을 사용하는 객체들은 앱 전역에서 동일한 인스턴스를 유지해야 하므로 Class로 구현
Struct
값을 복사하여 사용하는 것이 적절한 경우
Swift의 기본 타입(
Int
,Double
,String
,Array
,Dictionary
등)이 Struct인 이유와 동일하게, 값 타입은 복사되어 전달되므로 원본 데이터를 변경하지 않고도 안전하게 사용 가능예를 들어,
Int
나String
을 함수에 전달할 때 원본 값이 변경되지 않으며,Array
와Dictionary
도 Struct이므로 값이 변경될 때마다 새로운 복사본이 생성됨이는 데이터 변경이 독립적으로 이루어지도록 보장하는 중요한 원칙임
객체 간 공유가 필요하지 않은 경우
Strcut는 값 타입이므로, 하나의 인스턴스가 변경되더라도 다른 인스턴스에 영향을 주지 않음
예를 들어,
CGPoint
,CGRect
와 같은 UI 요소는 독립적으로 사용되며, 참조 공유가 필요하지 않기 때문에 Strcut로 구현됨이러한 요소들이 값 타입으로 동작하면, UI가 변경될 때 불필요한 복잡성이 줄어들고, 예기치 않은 부작용을 방지할 수 있다.
스레드 안정성이 필요한 경우
Struct는 값 복사가 이루어지므로 멀티스레드 환경에서도 안전하게 사용 가능
예를 들어, 여러 스레드에서 동일한 데이터를 동시에 읽고 수정해야 하는 경우, Struct를 사용하면 각 스레드가 독립적인 복사본을 가지므로 데이터 충돌(Race Condition)이 발생하지 않음
반면 Class는 같은 객체를 참조하므로, 동기화 작업을 추가적으로 고려해야 함
불변성을 유지해야 하는 경우
Struct는 값 타입이므로, 인스턴스가 변경될 때마다 새로운 복사본이 생성되며 원본 데이터는 변경되지 않음
예를 들어, SwiftUI의
View
는 Struct로 구현되어 있으며, 상태가 변경될 때마다 새로운View
가 생성되는 방식으로 동작함이는 UI 업데이트를 단순화하고, Side Effect 없이 상태 변화를 쉽게 추적할 수 있도록 도움
값을 비교하는 것이 중요한 경우
Struct는 값 자체를 저장하며,
Equatable
프로토콜을 자동으로 채택할 수 있어 쉽게 비교 가능예를 들어, 두 개의
CGRect
또는Data
값을 비교할 때, 같은 값을 가지면 같은 것으로 간주되므로 간단한==
연산으로 비교할 수 있음
Apple의 Swift 공식 문서에서도 기본적으로 Struct를 사용하고, 필요할 때만 Class를 사용하라고 권장한다. Struct는 값 타입이므로 데이터 변경이 독립적으로 이루어져 예측 가능성이 높고, 메모리 관리가 간단하기 때문이다. 반면 Class는 참조 타입으로 객체 공유가 필요하거나 상속이 필요한 경우에만 사용하는 것이 적절하다.