본문 바로가기

iOS/Swift

[Swift] Class와 Struct의 차이점

classstruct는 언뜻 보면 비슷해 보일 수 있다.

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

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

 

let vehicle1 = Vehicle()

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

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

 

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

 

1. 상속

classstruct는 상속 가능 여부에 차이가 있다.

결론적으로 말하면 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")
    }
}

 

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

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이라는 함수를 사용하면 vehicle2wheel 수는 어떻게 될까?

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

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

이것은 vehicle2vehicle1을 "참조"하고 있기 때문이고 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' 카테고리의 다른 글