본문 바로가기

iOS/Swift

[Swift] Class와 Struct의 차이점

`class`와 `struct`는 언뜻 보면 비슷해 보일 수 있다.

class Vehicle {
    var wheel = 4
    
    func move() {
        print("move forward")
    }
}
struct Vehicle {
    var wheel = 4
    
    func move() {
        print("move forward")
    }
}

다음 예시를 보면 `class`와 `struct`라는 이름만 달라졌지 그 이외에 달라진 것은 없어보인다. 

 

let vehicle1 = Vehicle()

또한 사용을 할 때도 위와 같이 같은 꼴이다 보니 두 가지를 굳이 왜 구분해놓았지?라고 생각할 수 있다.

왜냐? 내가 처음에 그랬으니까~

 

하지만 두개는 엄연히 다른 것이다.! 하나하나 어디가 다른지 같이 짚어보자.

 

1. 상속

`class`와 `struct`는 상속 가능 여부에 차이가 있다.

결론적으로 말하면 `struct`는 상속이 불가능하다!

 

`class`는 아래와 같은 방식으로 상속을 할 수 있다.

class Car: Vehicle{
    
}

상속을 하게 되면 부모클래스인 `Vehicle`내의 프로퍼티나 함수들을 자녀클래스인 `Car`에서 사용할 수 있다.

let car = Car()
car.move()
// 출력 : move forward

 

 

2. 초기화 (생성자)

`class`는 내부의 프로퍼티가 초기화되지 않은 상태라면 꼭 생성자를 써주어야한다.

`struct`는 생성자가 필요하지 않기 때문에 아래코드처럼 프로퍼티가 초기화되지 않은 상태로 존재해도 따로 오류가 나지 않는다.

struct Vehicle {
    var wheel: Int
    
    func move() {
        print("move forward")
    }
}

 

하지만 `class`에서는 `init`이라는 생성자를 써 주지 않으면 오류가 난다.

class Vehicle {
    var wheel: Int
    
    init(wheel: Int){
        self.wheel = wheel
    }
    
    func move() {
        print("move forward")
    }
}

 

하지만 또 두 개가 비슷해 보이는 것은 사용방법 때문인데, `class`와 `struct` 둘 다 아래와 같이 사용해야한다. 

let vehicle1 = Vehicle(wheel: 4)

`struct`는 생성자는 만들 필요가 없지만, 값이 없는 프로퍼티가 있어서는 안된다. 결국 같은 방식으로 사용해한다.

 

3. 참조

`class` 코드에 새로운 함수를 추가해보자. 

class Vehicle {
    var wheel: Int
    init(wheel: Int) {
        self.wheel = wheel
    }
    func move() {
        print("move forward")
    }
    
    func changeWheelNumber(amount: Int) {
        wheel = wheel - amount
    }
}
let vehicle1 = Vehicle(wheel: 10)
let vehicle2 = vehicle1

바퀴 수를 `10`이라고 두고, `vehicle2`라는 객체를 `vehicle1`과 같다고 만들어주었다. 

이 상태로 `changeWheelNumber`이라는 함수를 사용하면 `vehicle2`의 `wheel` 수는 어떻게 될까?

vehicle1.changeWheelNumber(amount: 3)
print(vehicle1.wheel)
print(vehicle2.wheel)
// 출력 : 7
// 출력 : 7

우리는 `vehicle2`의 `wheel`을 변경한 것이 아닌데도 불구하고 `vehicle2`의 `wheel` 값이 변했다는 것을 알  수 있다.

이것은 `vehicle2`가 `vehicle1`을 "참조"하고 있기 때문이고 `let vehicle2 = vehicle1`만으로는 새로운 객체를 생성한 것이 아닌 것을 알 수 있다.

`vehicle2`를 새로운 객체로 만들어주기 위해서는 `let vehicle2 = Vehicle(wheel: 10)`으로 생성자부터 써주어야한다.

 

이것을 `struct`로 써보자.

struct Vehicle {
    var wheel: Int

    func move() {
        print("move forward")
    }
    
    mutating func changeWheelNumber(amount: Int) {
        wheel = wheel - amount
    }
}

`struct`에서는 내부 프로퍼티의 값을 수정해야할 때, `mutating` 키워드를 꼭 써주어야한다. 

구조체는 값 타입인데 이것은 프로퍼티를 메서드 내에서 수정할 수 없다.

따라서`mutating`을 붙여줘서 구조체 전체를 새로 초기화시킴으로써 수정한다.

var vehicle1 = Vehicle(wheel: 10)
var vehicle2 = vehicle1
vehicle1.changeWheelNumber(amount: 3)
print(vehicle1.wheel)
print(vehicle2.wheel)
// 출력 : 7
// 출력 : 10

 

같은 코드를 써주었을 때, `vehicle1`을 상수로 설정해줄 수가 없는데, 

`mutating` 때문에 `struct` 전체가 변화하는 것이기 때문에 `var`로 써야한다. 

 

출력을 보게 되면 `vehicle2`의 값은 변하지 않은 것을 알 수 있다. 이것을 통해서 구조체는 참조가 아닌 "복사"를 해서 새로운 객체를 만들어 준다는 것을 알 수 있다.

'iOS > Swift' 카테고리의 다른 글

[Swift] while문의 구문이름표를 알아보자  (0) 2023.08.04
[Swift] String 관련 메서드 정리  (2) 2023.08.03
[Swift] 튜플 (Tuple) 알아보기  (0) 2023.08.02
[Swift] Map 알아보기  (1) 2023.08.01