티스토리 뷰

Swift 공식 가이드/Swift 2

Inheritance

찜토끼 2016. 4. 24. 15:42

Swift 3.0.1 가이드에 대응하는 정리글을 작성하였습니다!!!

Inheritance 정리 최신버전 링크 > http://wlaxhrl.tistory.com/46




Apple 제공 Swift 프로그래밍 가이드(2.2)의 Inheritance 부분을 공부하며 정리한 글입니다. 개인적인 생각도 조금 들어가있습니다.



들어가며

클래스는 다른 클래스로부터 메서드, 프로퍼티, 그 외 다른 특성들을 상속inheritance받을 수 있다. 상속을 받은 클래스를 서브클래스subclass, 상속을 해준 클래스를 슈퍼클래스superclass라고 부른다. 

서브클래스는 슈퍼클래스의 메서드, 프로퍼티, 스크립트에 접근할 수 있고, 재정의(오버라이딩)할 수도 있다.

상속받은 프로퍼티에 프로퍼티 옵저버를 추가할 수 있다. 지난번 프로퍼티 포스팅에 언급했던 것처럼, 슈퍼클래스의 computed 프로퍼티에도 서브클래스에서는 옵저버를 추가할 수 있다.



Defining a Base Class

베이스 클래스(Base Class) : 어떤 클래스도 상속받지 않은 클래스

<note> 스위프트에서는 모든 클래스가 상속받아야 할 universal base class가 특별히 없다. 따라서 아무 클래스도 상속받지 않은 클래스는 자연히 베이스 클래스가 된다.

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "현재 스피드는 \(currentSpeed)"
    }
    
    func makeNoise() {
        // 어떤 차일지에 따라 소리가 다르다
    }
}

let someVehicle = Vehicle()
print("Vehicle : \(someVehicle.description)")



Subclassing

서브클래싱은 기존 클래스(superclass)를 기반으로 하여 새로운 클래스(subclass)를 만드는 것이다. 서브클래스는 슈퍼클래스로부터 특성을 상속받고, 특성을 재정의할 수 있으며, 새로운 특성을 더할 수도 있다.

class SomeSubclass: SomeSuperclass {
    // subclass definition goes here
}


위에서 정의했던 베이스 클래스 Vehicle을 서브클래싱해보자.

class Bicycle: Vehicle {
    var hasBasket = false // 서브클래스만의 새로운 특성을 더했다
}

let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0 // 슈퍼클래스의 프로퍼티를 상속받음
print(bicycle.description) // 슈퍼클래스의 메서드를 상속받음


// 서브클래스를 상속할 수도 있다
class Tandem: Bicycle {
    var currentNumberOfPassengers = 0
}

let tandem = Tandem()
print(tandem.description)
// Vehicle에 있던 decription 프로퍼티를 Bicycle이 상속받았고,
// Tandem이 Bicycle을 상속받았으므로 당연히 description에 접근 가능하다



Overriding

서브클래스는 슈퍼클래스의 메서드, 프로퍼티, 서브스크립트를 재정의할 수 있는데, 이것을 오버라이딩이라고 부른다. (따로 재정의하지 않으면 슈퍼클래스의 구현체를 그대로 사용한다)

오버라이딩을 위해서는 해당 메서드, 프로퍼티, 서브스크립트의 정의 앞에 override 키워드를 붙여준다.

  • override 키워드가 붙었는데 슈퍼클래스에 정의되어 있는 것과 인터페이스가 일치하지 않으면 에러

  • override 키워드가 안붙었는데 슈퍼클래스에 정의되어 있는 것과 인터페이스가 일치하면 에러 


<Accessing Superclass Methods, Properties, and Subscripts>

서브클래스 안에서 슈퍼클래스의 메서드, 프로퍼티, 서브스크립트를 오버라이드했더라도 경우에 따라서는 슈퍼클래스의 것을 사용해야 할 경우가 있다. 그럴때는 super 를 통해 접근한다.

  • super.someMethod()

  • super.somProperty

  • super[someIndex]


<Overriding Methods>

class Train: Vehicle {
    override func makeNoise() {
        print("칙폭칙폭")
    }
}

let train = Train()
train.makeNoise()


<Overriding Properties>

메서드와 마찬가지로 프로퍼티도 오버라이드할 수 있다. 또한 상속받은 프로퍼티에 옵저버를 추가할 수도 있다.


<Overriding Property Getters and Setters>

class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}

상속받은 프로퍼티에 대해 custom getter/setter를 제공할 수 있다.

  • 즉, Computed 프로퍼티 형식으로 오버라이드하라는 것이다

  • 슈퍼클래스에서의 해당 프로퍼티가 Stored 프로퍼티여도 가능하다 (단 클래스 Stored 프로퍼티는 제외. 왜냐면 static 키워드를 붙여야만 정의할 수 있는데, static을 붙이면 overriding 할 수 없다.)

  • 서브클래스는 프로퍼티의 이름/타입만 알고 있으며 슈퍼클래스의 구현은 알지 못한다. 반대로 말하면 프로퍼티의 이름/타입을 명시해야 오버라이드 가능

  • 슈퍼클래스의 read-only(getter만 제공)프로퍼티를 서브클래스에서 read-writer(getter/setter 모두 제공)로 만드는 것은 가능하지만

  • 슈퍼클래스의 read-writer를 서브클래스에서 read-only로 만드는 것은 불가능. (즉, 이 경우는 getter만 오버라이드 불가능. getter/setter 모두 정의해주어야 한다) *부모가 가진 속성을 자식은 거부하면 안 된다(OOP 기본규칙 중 추상화 개념에 위배된다)

  • Computed 프로퍼티는 setter만 정의할 수 없는 것처럼, 프로퍼티 오버라이드의 경우에도 setter만 정의할 수 없다. getter도 반드시 같이 정의되어야 한다. 오버라이드 할 부분이 없다면 super.프로퍼티이름 이라도 넣어주어야 한다.


데...

stored 프로퍼티를 이런식으로 오버라이드하는 것은 왜 못하게 하는지... why?



<Overriding Property Observers>

프로퍼티 오버라이드를 사용하면 상속받은 프로퍼티에 옵저버를 추가할 수 있다.

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "현재 스피드는 \(currentSpeed)"
    }
    
    func makeNoise() {
        // 어떤 차일지에 따라 소리가 다르다
    }
}

// currentSpeed에 옵저버를 추가하기 위해 프로퍼티 오버라이드를 사용한다
class Car: Vehicle {
    var maxSpeed = 0.0
    override var currentSpeed: Double {
        willSet {
            if (newValue > maxSpeed) {
                maxSpeed = newValue
            }
        }
    }
}

var car = Car()
car.maxSpeed // 0
car.currentSpeed = 10.0
car.maxSpeed //10


// <추가설명> 이때 슈퍼클래스에도 currentSpeed에 옵저버가 걸려있다면
// 그것도 같이 불리게 된다. 아래 예시를 보자.

class Vehicle {
    var currentSpeed = 0.0 {
        willSet {
            print("willSet in super")
        }
    }
}

class Car: Vehicle {
    override var currentSpeed: Double {
        willSet {
            print("willSet in sub")
        }
    }
}

let car = Car()
car.currentSpeed = 3
// willSet in sub, willSet in super 둘 다 출력됨

// 위 상황에서 슈퍼클래스의 옵저버가 불리지 않게 하고 싶다면
// 프로퍼티의 setter, getter를 오버라이드 하면 된다고 하는데
// 여러가지로 시도해봤지만 상당히 코드가 더러워졌다
// 구글링을 해본 결과 다음과 같은 구조가 깔끔한 것 같다
// (http://stackoverflow.com/questions/29503482/override-property-observer)

class Vehicle {
    var currentSpeed = 0.0 {
        willSet {
            self.willCurrentSpeedChange()
        }
    }
    
    func willCurrentSpeedChange() {
        print("willSet in super")
    }
}

class Car: Vehicle {
    override func willCurrentSpeedChange() {
        print("willSet in sub")
    }
}


<note> 다음과 같은 예외사항들이 있다.

  • 상수 Stored 프로퍼티, getter만 있는 read-only Computed 프로퍼티에 옵저버를 추가하는 것은 불가. (변하지 않는 값이기 때문에 불필요)

  • 프로퍼티의 setter와 옵저버를 둘 다 오버라이드 하는 것은 불가능. (setter를 오버라이드 했다면 그 안에서 값의 변화를 탐지하도록 하자)



Preventing Overrides

서브클래스에서 오버라이드를 못하게 하고 싶다면 해당 메서드, 프로퍼티, 스크립트 정의 앞에 final 키워드를 붙인다.

'Swift 공식 가이드 > Swift 2' 카테고리의 다른 글

Initialization (2/3)  (0) 2016.05.06
Initialization (1/3)  (0) 2016.05.05
Subscripts  (0) 2016.04.23
Methods  (0) 2016.04.17
Properties  (1) 2016.04.13
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함