Swift문법 - (15)타입캐스팅

Youth·2022년 10월 2일
0

swift문법공부

목록 보기
15/27
post-thumbnail

타입캐스팅(Type Casting)

  • 인스턴스 타입을 검사 - is 연산자
  • 클래스 계층 상의 타입 변환 - as 연산자

is연산자

상속 : 기본적으로 저장속성을 추가하는 관점에서 생각

  • 상속을 하면할수록 저장속성이 추가된다(점점더 커진다)
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 = "전공"
}

사람 인스턴스는 학생/대학생 타입은 아니다. (사람 타입이다.)

person1 is Person                // true

person1 is Student               // false

person1 is Undergraduate         // false

학생 인스턴스는 대학생 타입은 아니다.  (사람/학생 타입니다.)

student1 is Person               // true

student1 is Student              // true

student1 is Undergraduate        // false

대학생 인스턴스는 사람이거나, 학생이거나, 대학생 타입 모두에 해당한다.

undergraduate1 is Person         // true

undergraduate1 is Student        // true

undergraduate1 is Undergraduate  // true

💡 is 연산자는 포함관계를 생각하면 편하다 ”왼쪽 is 오른쪽”이라면 왼쪽이 오른쪽을 포함할수있니를 물어본다고 생각

as연산자

예를들어서 Person타입으로 선언한 변수에 Undergraduate인스턴스를 담는다면

let person: Person = Undergraduate()

Undergrauate인스턴스는 id, name, email, studentId, major를 모두 가지고 있지만

person변수에는 Person이 들어있다고 인지를 하기 때문에(Person형식의 박스)

✅studentId와 major변수에는 접근이 불가능하다✅

let ppp = person as? Undergraduate

ppp라는 변수에 person이라는 변수의 타입을 Undergraduate로 바꿔서 저장

(optional Undergraduate타입이기때문에 옵셔널 바인딩이 필요하다)

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

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

언래핑이 가능한걸보니 person(실제로는 Person타입)의 타입을 변환시키는데 성공

let person: Person = Undergraduate()

변수를 선언할때 Undergraduate인스턴스를 생성하기 때문에 저장속성이 5개로 메모리에 올라가게된다

하지만 실제로는 3개만 보이도록(Person타입으로 담는다) 되어있다

💡 as? → 언래핑 해줘야함, as! → 강제 언래핑됨(nil이면 오류 발생)
let person: Person = Person()
let ppp = person as? Undergraduate
// 위와같은 방식은 nil을 반환하게 된다 처음부터 3개의 저장속성을 가지고 있는데
// Undergraduate로 다운캐스팅은 불가능하다

타입과 다형성(Polymorphism)

  • 상속관계에서 인스턴스의 다형성에 대한 이해
  • 하나의 객체(인스턴스)가 여러가지의 타입의 형태로 표현될 수 있음을 의미
// 이런게 가능하다는 의미
let person: Person = Undergraduate()
  • 타입의 저장 형태는 속성/메서드에 대한 접근가능 범위를 나타내는 것이고, 다형성은 인스턴스에서 메모리의 실제 구현 내용에 대한 것임 (메서드는 재정의 가능하고, 메서드 테이블을 통해 동작)

Any와 AnyObject를 위한 타입 캐스팅

  • 스위프트에서는 제공하는 불특정한 타입을 다룰 수 있는 타입을 제공
  1. Any 타입
  • 기본 타입(Int, String, Bool, ...) 등 포함, 커스텀 클래스, 구조체, 열거형, 함수타입
    까지도 포함해서 어떤 타입의 인스턴스도 표현할 수 있는 타입 (옵셔널타입도 포함)
  1. AnyObject 타입
  • 어떤 클래스 타입의 인스턴스도 표현할 수 있는 타입
var some: Any = "Swift"
(some as! String).count
some = 10
some = 3.2
// 단점
// 저장된 타입의 메모리 구조를 알 수없기 때문에, 항상 타입캐스팅해서 사용해야함
  1. 구체적인 타입 : String, Int, Double ------> 범용적인 타입 : Any

====> 업캐스팅(as)

  1. 범용적인 타입 : Any ------> 구체적인 타입 : String, Int, Double

====> 다운캐스팅(as!,?)

💡 그냥 편안하게 Any가 범위가 작은거라고 거꾸로 생각하면 마음이 편하다
let objArray: [AnyObject] = [Person(), Superman(), NSString()]

//objArray[0].name 는 접근이 불가능하다 AnyObject니까 무조건 타입캐스팅
(objArray[0] as! Person).name
// AnyObject는 범위가 작은거(아니지만 내가 외우는방법)니까 Person으로 다운캐스팅

타입캐스팅 + 분기처리

// 타입캐스팅 + 분기처리

for (index, item) in array.enumerated() {
    // (0,  5)
    // (1, "안녕")
    // (2, 3.5)
    // ...
    
    switch item {
    // item is Int
    case is Int:                                 
        print("Index - \(index): 정수입니다.")

		// let num = item as Double
    case let num as Double:                       
        print("Index - \(index): 소수 \(num)입니다.")

		// item is String
    case is String:                               
        print("Index - \(index): 문자열입니다.")

		// let person = item as Person
    case let person as Person:                    
        print("Index - \(index): 사람입니다.")
        print("이름은 \(person.name)입니다.")
        print("나이는 \(person.age)입니다.")

		// item is (String) -> String
    case is (String) -> String:                   
        print("Index - \(index): 클로저 타입입니다.")
    default:
        print("Index - \(index): 그 이외의 타입입니다.")
    }
}

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

옵셔널 값의 Any 업캐스팅

let optionalNumber: Int? = 3
print(optionalNumber)          // 노란색 경고
print(optionalNumber as Any)   // 노란색 경고 없음
profile
AppleDeveloperAcademy@POSTECH 1기 수료, SOPT 32기 iOS파트 수료

0개의 댓글