구조체와 클래스는 프로그래머가 데이터를 용도에 맞게 묶어서 표현하고자 할 때 유용한데, 이 둘의 큰 차이점은 구조체의 인스턴스는 값 타입이고 클래스의 인스턴스는 참조 타입이라는 것이다.
구조체는 struct 키워드로 정의한다. 구조체를 정의한다는 것은 새로운 타입을 생성해주는 것과 마찬가지이므로 Int, Float, String과 같이 대문자 카멜케이스를 사용하여 이름을 지어준다.
struct Student {
var name: String
var age: Int
}
구조체를 정의했으면 이 구조체의 인스턴스를 생성해야 할텐데, 구조체에 기본적으로 생성되는 멤버 와이즈 이니셜라이저를 사용하여 인스턴스를 생성하고 초기화할 수 있다.
var myInfo: Student = Student(name: "silverCastle", age: 24)
print("제 이름은 \(myInfo.name)입니다.")
print("제 나이는 \(myInfo.age)입니다.")
결과
제 이름은 silverCastle입니다.
제 나이는 24입니다.
만약, 구조체를 let으로 선언한다면?
구조체의 인스턴스는 값 타입이므로 인스턴스 내부의 프로퍼티 값을 변경할 수 없음을 명심하자.
let yourInfo: Student = Student(name: "bronzeCastle", age: 25)
yourInfo.name = "goldCastle"
결과
Cannot assign to property: 'yourInfo' is a 'let' constant
클래스는 class 키워드로 정의한다. 클래스도 구조체와 마찬가지로 대문자 카멜케이스를 사용하여 이름을 지어준다.
클래스를 정의하는 방법은 구조체와 흡사하지만 클래스는 상속받을 수 있기 때문에 상속 받을 경우에는 클래스 이름 뒤에 콜론(:)을 써주고 부모클래스를 명시한다.
만약, 클래스를 let으로 선언한다면?
클래스의 인스턴스는 참조 타입이므로 인스턴스 내부의 프로퍼티 값을 변경할 수 있음을 명심하자.
class Person {
var height: Float = 0.0
var weight: Float = 0.0
}
var me: Person = Person()
me.height = 175
me.weight = 74
print("내 키는 \(me.height)입니다.")
print("내 몸무게는 \(me.weight)입니다.")
let you: Person = Person()
you.height = 156
you.weight = 50
print("당신의 키는 \(you.height)입니다.")
print("당신의 몸무게는 \(you.weight)입니다.")
결과
내 키는 175.0입니다.
내 몸무게는 74.0입니다.
당신의 키는 156.0입니다.
당신의 몸무게는 50.0입니다.
또한, 클래스의 인스턴스는 더는 참조할 필요가 없을 때 메모리에서 해제되는데 이 과정을 소멸이라고 한다. 소멸되기 직전 deinit라는 메서드가 호출된다. deinit 메서드는 클래스당 하나만 구현할 수 있으며, 매개변수와 반환 값을 가질 수 없는 게 특징이다.
class Person {
var height: Float = 0.0
var weight: Float = 0.0
deinit {
print("Person 클래스의 인스턴스가 소멸됩니다.")
}
}
var me: Person? = Person()
me = nil
결과
Person 클래스의 인스턴스가 소멸됩니다.
공통점
차이점
앞서 말했다시피, 가장 큰 차이점은 구조체의 인스턴스는 값 타입이고 클래스의 인스턴스는 참조 타입이라는 것인데 예를 들어, 어떤 함수의 전달인자로 값 타입의 값을 넘긴다면 전달될 값이 복사되어 전달되지만 전달인자로 참조 타입이 전달된다면 값을 복사하지 않고 참조가 전달된다. 여기서 참조는 주소라고 생각하면 된다.
구조체
struct Student {
var name: String
var age: Int
}
var myInfo: Student = Student(name: "silverCastle", age: 24)
myInfo.age = 100
var yourInfo: Student = myInfo
print("내 나이는 \(myInfo.age)입니다.")
print("당신의 나이는 \(yourInfo.age)입니다.")
yourInfo.age = 200
print("내 나이는 \(myInfo.age)입니다.")
print("당신의 나이는 \(yourInfo.age)입니다.")
결과
내 나이는 100입니다.
당신의 나이는 100입니다.
내 나이는 100입니다.
당신의 나이는 200입니다.
클래스
class Person {
var height: Float = 0.0
var weight: Float = 0.0
}
var me: Person = Person()
me.height = 175
me.weight = 74
let you: Person = me
print("내 키는 \(me.height)입니다.")
print("당신의 키는 \(you.height)입니다.")
you.height = 156
print("내 키는 \(me.height)입니다.")
print("당신의 키는 \(you.height)입니다.")
결과
내 키는 175.0입니다.
당신의 키는 175.0입니다.
내 키는 156.0입니다.
당신의 키는 156.0입니다.
이제 구조체와 클래스의 공통점과 차이점을 알게 되었다. 그렇다면 언제 구조체를 쓰고 언제 클래스를 써야할까?
애플은 가이드라인에서 다음 조건 중 하나라도 해당된다면 구조체를 사용하라고 권장하고 있다.