[Swift 정면돌파] 10. 상속과 타입 캐스팅

H43RO·2021년 8월 5일
1

Swift 정면돌파

목록 보기
10/19
post-thumbnail

오늘은 스위프트에서의 상속과 타입 캐스팅에 대하여 알아보았다. 개인적인 견해이지만, 스위프트에서는 상속이라는 개념을 그렇게 중요시하지 않는 것 같다. 워낙 스위프트의 꽃인 '프로토콜 및 익스텐션'의 포텐셜이 엄청나서 그런지, 이러한 것들의 사용을 더 권장하는 것 같다. 그리고 개인적으로 재정의를 허용하는 타입 메소드 라는 것을 명시하기 위한 class 키워드가 너무 익숙하지 않다. 몇 번을 다시 봐도 괴이하다 (?)

상속

스위프트에서의 상속

  • 상속은 클래스, 프로토콜 등에서 가능함
  • 열거형, 구조체 등은 상속 불가능 (값 타입은 상속 불가!)
  • 스위프트 클래스는 단일상속으로, 다중 상속 지원 안 함

문법

class 이름: 상속받을 클래스 이름 {
    /* 구현부 */
}

사용

  • final 키워드를 사용하면 재정의 (Override) 방지 가능
  • static 키워드를 사용해 타입 메소드를 만들면 재정의 불가능
  • class 키워드를 사용해 타입 메소드를 만들면 재정의 가능
  • class 앞에 final 을 붙이면 static 키워드를 사용한 것과 동일
  • override 키워드를 사용하여 부모 클래스 메소드 재정의 가능
// 기반 클래스 Person
class Person {
    var name: String = ""
    
    func selfIntroduce() {
        print("저는 \(name)입니다")
    }
    
    // final 키워드를 사용하여 재정의를 방지
    final func sayHello() {
        print("hello")
    }
    
    // 타입 메서드
    // 재정의 불가 타입 메서드 - static
    static func typeMethod() {
        print("type method - static")
    }
    
    // 재정의 가능 타입 메서드 - class
    class func classMethod() {
        print("type method - class")
    }
    
    // 재정의 가능한 class 메서드라도 
    // final 키워드를 사용하면 재정의 할 수 없음
    // 메서드 앞의 static 과 final class 는 같은 역할
    final class func finalCalssMethod() {
        print("type method - final class")
    }
}

// Person을 상속받는 Student
class Student: Person {
    var major: String = ""
    
    override func selfIntroduce() {
        print("저는 \(name)이고, 전공은 \(major)입니다")
    }
    
    override class func classMethod() {
        print("overriden type method - class")
    }
    
    // static을 사용한 타입 메서드는 재정의 할 수 없음
//    override static func typeMethod() {    }
    
    // final 키워드를 사용한 메서드, 프로퍼티는 재정의 할 수 없음
//    override func sayHello() {    }
//    override class func finalClassMethod() {    }

}

구동 확인

let yagom: Person = Person()
let hana: Student = Student()

yagom.name = "H43RO"
hana.name = "hana"
hana.major = "Swift"

yagom.selfIntroduce()
// 저는 H43RO입니다

hana.selfIntroduce()
// 저는 hana이고, 전공은 Swift입니다

Person.classMethod()
// type method - class

Person.typeMethod()
// type method - static

Person.finalCalssMethod()
// type method - final class

Student.classMethod()
// overriden type method - class

Student.typeMethod()
// type method - static

Student.finalCalssMethod()
// type method - final class

타입 캐스팅

스위프트에서의 타입 캐스팅

→ 인스턴스의 타입을 확인하는 용도
→ 클래스의 인스턴스를 부모, 자식 클래스의 타입으로 사용할 수 있는지 확인하는 용도
is, as 사용

class Person {
    var name: String = ""
    func breath() {
        print("숨을 쉽니다")
    }
}

class Student: Person {
    var school: String = ""
    func goToSchool() {
        print("등교를 합니다")
    }
}

class UniversityStudent: Student {
    var major: String = ""
    func goToMT() {
        print("멤버쉽 트레이닝을 갑니다 신남!")
    }
}

// 인스턴스 생성
var haero: Person = Person()
var lulu: Student = Student()
var jason: UniversityStudent = UniversityStudent()

타입 확인

is 키워드를 통해 타입 확인 가능

var result: Bool

result = haero is Person // true
result = haero is Student // false
result = haero is UniversityStudent // false

result = lulu is Person // true
result = lulu is Student // true
result = lulu is UniversityStudent // false

result = jason is Person // true
result = jason is Student // true
result = jason is UniversityStudent // true

if haero is UniversityStudent {
    print("haero은 대학생입니다")
} else if haero is Student {
    print("haero은 학생입니다")
} else if haero is Person {
    print("haero은 사람입니다")
} // haero은 사람입니다

// 스위프트는 switch 문 케이스 각각에 기본적으로 break 동작을 포함하고 있어
// 먼저 조건에 부합되는 분기에서 switch 문이 실행 종료됨

switch jason {
case is Person:
    print("jason은 사람입니다")
case is Student:
    print("jason은 학생입니다")
case is UniversityStudent:
    print("jason은 대학생입니다")
default:
    print("jason은 사람도, 학생도, 대학생도 아닙니다")
} // jason은 사람입니다

switch jason {
case is UniversityStudent:
    print("jason은 대학생입니다")
case is Student:
    print("jason은 학생입니다")
case is Person:
    print("jason은 사람입니다")
default:
    print("jason은 사람도, 학생도, 대학생도 아닙니다")
} // jason은 대학생입니다

업 캐스팅

as 를 사용하여 부모 클래스의 인스턴스로 사용할 수 있도록 컴파일러에게 타입 정보를 전환해 줌
Any 혹은 AnyObject 로도 타입 정보를 변환할 수 있음
→ 암시적으로 처리되므로 꼭 필요한 경우가 아니라면 생략해도 무방

// UniversityStudent 인스턴스를 생성하여 Person 행세를 할 수 있도록 업 캐스팅
var mike: Person = UniversityStudent() as Person

var jenny: Student = Student()
// var jina: UniversityStudent = Person() as UniversityStudent // 컴파일 오류

// UniversityStudent 인스턴스를 생성하여 Any 행세를 할 수 있도록 업 캐스팅
var jina: Any = Person() // as Any 생략가능

다운 캐스팅

as? 또는 as! 를 사용하여 자식 클래스의 인스턴스로 사용할 수 있도록
컴파일러에게 인스턴스의 타입 정보를 전환해줌

조건부 다운 캐스팅

  • as? 를 사용
  • 캐스팅 실패시 nil 반환하기 때문에 결과 타입은 옵셔널임
var optionalCasted: Student?

optionalCasted = mike as? UniversityStudent
optionalCasted = jenny as? UniversityStudent // nil
optionalCasted = jina as? UniversityStudent // nil
optionalCasted = jina as? Student // nil

강제 다운 캐스팅

  • as! 를 사용
  • 캐스팅 실패시 런타임 오류 발생
  • 캐스팅 성공시 일반 타입 반환 (옵셔널 X)
var forcedCasted: Student

forcedCasted = mike as! UniversityStudent
//forcedCasted = jenny as! UniversityStudent // 런타임 오류
//forcedCasted = jina as! UniversityStudent // 런타임 오류
//forcedCasted = jina as! Student // 런타임 오류

활용

func doSomethingWithSwitch(someone: Person) {
    switch someone {
    case is UniversityStudent:
        (someone as! UniversityStudent).goToMT()
    case is Student:
        (someone as! Student).goToSchool()
    case is Person:
        (someone as! Person).breath()
    }
}

doSomethingWithSwitch(someone: mike as Person) // 멤버쉽 트레이닝을 갑니다 신남!
doSomethingWithSwitch(someone: mike) // 멤버쉽 트레이닝을 갑니다 신남!
doSomethingWithSwitch(someone: jenny) // 등교를 합니다
doSomethingWithSwitch(someone: yagom) // 숨을 쉽니다

func doSomething(someone: Person) {
    if let universityStudent = someone as? UniversityStudent {
        universityStudent.goToMT()
    } else if let student = someone as? Student {
        student.goToSchool()
    } else if let person = someone as? Person {
        person.breath()
    }
}

doSomething(someone: mike as Person) // 멤버쉽 트레이닝을 갑니다 신남!
doSomething(someone: mike) // 멤버쉽 트레이닝을 갑니다 신남!
doSomething(someone: jenny) // 등교를 합니다
doSomething(someone: yagom) // 숨을 쉽니다
profile
어려울수록 기본에 미치고 열광하라

0개의 댓글