swift study 14. 타입캐스팅 (Type Casting)

jess·2022년 7월 22일
0

Swift

목록 보기
14/19
post-thumbnail

🍃 출처 : 앨런 swift 문법 마스터 스쿨 수업을 듣고 제가 이해한대로 정리해서 올리는 포스팅입니다.

📓 타입캐스팅 (Type Casting)

13-2

표현식 is Type
  • 인스턴스의 "타입"을 확인 하거나, 해당 인스턴스를 슈퍼 클래스나 하위 클래스로 취급하는 방법
  • swift에서 타입 캐스팅은 is 나 as 연산자로 구현하며,
    타입 캐스팅을 사용하여 타입이 프로토콜에 적합한지 여부도 확인할 수 있다

1) is 연산자 (이항연산자)

: 타입을 체크하는 연산자 (type check operater)

  • 참이면 true, 거짓이면 false 리턴
    let char: Character = "A"
    char is Character //true
    char is String // false

예시1

class Human { }
class Teacher: Human { }

let teacher = Teacher()
teacher is Teacher   //true
teacher is Human     //ture
 - Human 클래스를 Teacher이란 클래스가 상속 받을 경우, 
 teacher이란 인스턴스는 Human클래스의 서브 클래스이기 때문에, 
 이런 경우엔 Human으로 타입 체크를 해도 true가 됨

예시2

class Human {
    let name: String
    init(name: String) {
        self.name = name
    }
}
class Teacher: Human { }
class Student: Human { }

let people: [Human] = [
    Teacher.init(name: "Jess"),
    Student.init(name: "Chris")]
  • Human이란 클래스가 있고, 이 Human 클래스를 상속받는 서브클래스
    Teacher 과 Student가 있음
    그리고 people 이라는 배열에 Teacher 인스턴스1개, Student 인스턴스1개 담음
    이것을 아래와 같이 타입 캐스팅을 통해 확인하며 조건문을 분기할 수 있음
for human in people {
    if human is Teacher {
        print("선생님 : \(human.name)")
    } else if human is Student {
        print("제자 : \(human.name)")
    }
}
// 선생님 : Jess
// 제자 : Chris

예시3

class Person {
    var id = 0
    var name = "이름"
    var email = "abc@gmail.com"
}

class Student: Person {
    // id
    // name
    // email
    var studentId = 1
}


class Undergraduate: Student {
    // id
    // name
    // email
    // studentId
    var major = "전공"
}

let person1 = Person()
person1.id
person1.name
person1.email

let student1 = Student()
student1.id
student1.name
student1.email
student1.studentId // 추가적으로

let undergraduate1 = Undergraduate()
undergraduate1.id
undergraduate1.name
undergraduate1.email
undergraduate1.studentId
undergraduate1.major    //  추가적으로

2) as 연산자 (다운캐스팅 / as? , as!)

표현식 as (변환 할)Type
표현식 as? (변환 할)Type
표현식 as! (변환 할)Type
  • 표현식(의 타입)이 변환할 type과 호환된다면, 변환할 type으로 캐스팅된 인스턴스를 리턴한다.
  • 상속관계인 업캐스팅(upcasting)과 다운캐스팅(down casting)에서 사용한다
  • Any와 Anyobject 타입을 사용할 경우, 상속관계가 아니어도 예외적으로 사용할 수 있다.


✏️ 업캐스팅(Upcasting)

  • 서브 클래스 인스턴스를 "슈퍼클래스의 타입" 으로 참조한다.
  • 업 캐스팅은 항상 성공
  • 상위 클래스의 메모리 구조로 인식
  • 상호 호환 가능한 타입도 항상 성공

예시

class Human {
    let name: String
    init(name: String) {
        self.name = name
    }
}
class Teacher: Human { }
class Student: Human { }

let people: [Human] = [
    Teacher.init(name: "Jess"),
    Student.init(name: "Chris")]
  • Teacher과 Student의 슈퍼클래스가 Human으로 동일하기 때문에,
    이 둘을 Human이란 클래스로 업캐스팅하여 묶어버린 것

✏️ 다운캐스팅(Downcasting)

  • 슈퍼클래스의 인스턴스를 <서브클래스의 타입> 으로 참조한다
  • 업캐스팅된 인스턴스를 다시 원래 서브 클래스 타입으로 참조할 때 사용한다
  • 다운 캐스팅은 실패할 수 있기에 as?, as! 연산자를 이용한다

예시

class Person {
   var id = 0
   var name = "이름"
   var email = "abc@gmail.com"
}


class Student: Person {
   // id
   // name
   // email
   var studentId = 1
}


class Undergraduate: Student {
   // id
   // name
   // email
   // studentId
   var major = "전공"
}


let person: Person = Person()
person.id
person.name
person.email
//person.studentId    // Value of type 'Person' has no member 'studentId'
//person.major          // Value of type 'Person' has no member 'major'

// 그런데, 왜 studentId 와 major 속성에는 접근이 되지 않을까? ⭐️

// person2변수에는 Person타입이 들어있다고 인식되는 것임
// ===> 그래서 접근불가 ===> 접근하고 싶다면 메모리구조에 대한 힌트(타입)를 변경 필요

let ppp = person as? Undergraduate  // Undergraduate? 타입
                                   // ppp는 옵셔널 Undergraduate

//사용하고 싶다면 if let 바인딩과 함께 사용 (옵셔널 언래핑)
if let newPerson = person as? Undergraduate {  
   newPerson.major
   print(newPerson.major)
}

// 실제로 인스턴스의 접근 범위를 늘려주는 것 뿐임
let person3: Undergraduate = person as! Undergraduate
person3.major

1) 인스턴스 as? 타입
타입캐스팅
- 성공 : Optional 타입으로 리턴 ➡️ 필요한 경우, 언래핑 필요
- 실패 : nil 리턴

2) 인스턴스 as! 타입
타입캐스팅
- 성공 : Optional 타입을 강제 언래핑한 타입
- 실패 : 런타임 오류

📓 상속과 다형성

13-3

다형성(Polymorphism)

  • 하나의 객체(인스턴스)가 여러가지의 타입 형태로 표현될 수 있음
    (또는 하나의 타입으로 여러 종류의 객체(인스턴스)를 여러가지 형태(모습)으로 해석될 수 있는 성격)
  • 다형성은 클래스의 상속(+프로토콜)과 깊은 연관성이 있음

✏️ 상속을 통한 메서드의 재정의와 다형성

  - 하나의 인스턴스는 업캐스팅된 타입(Person)으로 인식되고, 호출되더라도
   실제 인스턴스 형태(Undergraduate)에 따라 재정의된 메서드가 호출되고 실행

📓 Any와 AnyObject

13-4

불특정한 타입을 다룰 수 있는 타입 (범용적인 타입)

 1) Any 타입
 - 기본 타입(Int, String, Bool, ...) 등 포함, 커스텀 클래스, 구조체, 열거형, 함수타입
   까지도 포함해서 어떤 타입의 인스턴스도 표현할 수 있는 타입 (옵셔널타입도 포함)
  2) AnyObject 타입
 - 어떤 클래스 타입의 인스턴스도 표현할 수 있는 타입
   (클래스의 인스턴스만 담을 수 있음)

✏️ switch문과 타입캐스팅 연산자 (타입캐스팅 패턴)

switch item {
case is Int:
    print("정수")
case let num as Double:
    print("\(num)")
default:
    print("그 외의 타입")
}

0개의 댓글