클래스는 메소드, 프로퍼티와 다른 특징을 다른 클래스로 부터 상속할 수 있다.
이것이 Swift에서 클래스가 다른 타입과 구분되는 근본적인 요소이다. 클래스에서는 저장된 프로퍼티와 계산된 프로퍼티와 상관없이 상속받은 프로퍼티에 프로퍼티 옵저버를 설정해서 값 설정에 반응할 수 있다.
다른 어떤 클래스로부터도 상속받지 않은 클래스를 기반 클래스라 한다.
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// do nothing - an arbitrary vehicle doesn't necessarily make a noise
}
}
위 코드는 Vehicle
이라는 기반 클래스를 하나 정의한 것이다. 이 Vehicle
은 currentSpeed
이라는 0.0의 초기값을 갖고 있는 Double 타입의 프로퍼티가 있다. currentSpeed
프로퍼티의 값은 description
이라는 읽기 전용의 계산된 String 타입의 프로퍼티에서 사용되었다. makeNoise()
라는 메소드도 갖고 있다.
이 Vehicle
클래스를 이용해 someVehicle
이라는 새로운 인스턴스를 만든다.
let someVehicle = Vehicle()
someVehicle
이라는 인스턴스를 통해 Vehicle
클래스 내부의 description
프로퍼티에 접근이 가능하다.
print("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour
상속, 다시 말해 서브클래싱을 하면 부모로 부터 성격을 상속받고 자기 자신 고유의 특성도 추가할 수 있다.
class SomeSubclass: SomeSuperclass {
// subclass definition goes here
}
위의 예제를 이용해 설명하자면,
class Bicycle: Vehicle {
var hasBasket = false
}
Bicycle
은 Vehicle
을 서브클래싱하고 자기 자신의 속성 hasBasket
도 추가한다.
let bicycle = Bicycle()
bicycle.hasBasket = true
Bicycle
객체를 생성해 고유 속성을 사용할 수 있는 것을 확인할 수 있다.
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour
물론 부모로부터 물려받은 속성도 사용 가능하다.
서브클래스로 생성된 클래스를 다시 서브클래싱하는 것도 가능하다.
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
위 예제를 통해 다시 한 번 모든 설명을 대신한다.
서브클래스에서는 부모클래스에서 상속받은 것을 재정의 할 수 있다. 이것을 overriding
이라 부르는데, 오버라이딩은 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼피, 타입 프로퍼티, 서브스크립트 모두에 대해 가능하다. 오버라이드를 위해서는 다른 선언 앞에 override
키워드를 붙여준다. Swift에서는 override
키워드를 보면 부모에 그 정의가 있는지 확인한다.
super
키워드와 점문법 혹은 인덱스 구문으로 부모 클래스의 메소드, 프로퍼티, 서브스크립트에 접근할 수 있다. super.someMethod
, super.someProperty
, super[someIndex]
상속받은 메소드를 오버라이드 하기 위해서는 메소드 선언 앞에 override
키워드를 붙이고 내용을 적으면 된다.
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
}
let train = Train()
train.makeNoise()
// "Choo Choo" 출력
서브클래스에서는 상속받은 저장된 프로퍼티, 계산된 프로퍼티 모두 오버라이드 가능하다. 서브클래스에서는 단순히 상속받은 특정 타입의 프로퍼티가 있다는 정도만 알고 있기 때문에 오버라이드시에는 프로퍼티의 이름과 타입을 명시해야한다.
상속받은 읽기 전용 프로퍼티도 getter / setter
를 정의해서 읽고/쓰기가 가능한 프로퍼티로 변경해서 제공 가능하다. 하지만 반대로 읽고/쓰기가 가능한 프로퍼티를 읽기 전용 프로퍼티로 선언하는 것은 할 수 없다.
계산된 프로퍼티 오버라이딩 예시
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
}
오버라이딩한 프로퍼티가 재정의한대로 출력되는 것을 확인
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// "Car: traveling at 25.0 miles per hour in gear 3" 출럭
이미 부모클래스에 선언된 프로퍼티 옵저버도 서브클래스에서 재정의해 사용할 수 있다.
다음은 옵저버 오버라이드의 예제이다.
부모의 currentSpeed
계산된 프로퍼티를 오버라이드 했다.
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}
코드 실행결과 오버라이드한 내용이 출력되는 것을 확인할 수 있다.
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4
서브클래스에서 특정 메소드, 프로퍼티, 서브스크립트가 오버라이드 되는 것을 방지하려면 final
키워드를 사용한다. 다시말해, final
로 선언되면 override
되는 것을 막을 수 있다. 만일 final
로 선언된 메소드, 프로퍼티, 서브스크립트를 오버라이드 하려고 하면 컴파일 시간에 에러가 발생한다. 클래스 전체를 final
로 선언해서 클래스 안의 모든 메소드, 프로퍼티 등이 override
가 되는 것을 막을 수 있다.