seong_hye, the developer

Swift) 문법 정리 - 타입 캐스팅(Type Casting) / Any, AnyObject 본문

IOS

Swift) 문법 정리 - 타입 캐스팅(Type Casting) / Any, AnyObject

seong_hye 2022. 7. 12.

타입 캐스팅이란?

인스턴스의 타입을 확인하거나 어떠한 클래스의 인스턴스를

해당 클래스 계층 구조의 슈퍼클래스나 서브 클래스로 취급하는 방법

 

- 메모리 값을 수정하는 것은 아님

- 단순히 해당 타입의 인스턴스인 것처럼 취급하려는 목적

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

class Student: Person {
	var studentId = 1
}

class Undergraduate: Student {
	var major = "전공"
}

let person = Person()
let student = Student()
let undergraduate = Undergradutae()

is 연산자

타입에 대한 검사를 수행하는 연산자 (이항연산자)

참이면 true / 거짓이면 false

 

~>  상속관계의 하위 클래스는 상위 클래스를 포함하고 있기 때문에 true

person is Person 			//true
person is Student 			//false
person is Undergraduate 	//false

student is Person			//true
student is Student			//true
student is Undergraduate	//false

undergraduate is Person		//true
undergraduate is Student	//true
undergraduate is Undergraduate	//true

as 연산자

인스턴스의 타입의 힌트를 변경하는 연산자

 

업캐스팅(Upcasting) - as 타입

하위클래스의 메모리 구조로 저장된 인스턴스를 상위 클래스 타입으로 인식

타입 캐스팅 항상 성공

상호 호환가능한 타입도 항상 성공

// 업캐스팅
let student2 = student as Person
let undergraduate2 = undergraduate as Student

 

다운캐스팅(Downcasting) - as? / as!

상위클래스의 메모리 구조로 저장된 인스턴스를 하위 클래스 타입으로 인식

실패할 수도 있기때문에, 두 가지 연산자 존재

          

as?

- 성공: Optional 타입으로 리턴 -> 필요한 경우, 언래핑 필요

- 실패: nil 리턴

as!

- 성공: Optional 타입을 강제 언래핑한 타입

- 실패: 런타임 오류

 

다운캐스팅 성공에 대한 확신이 있을 때는 as! 를 사용, 그렇지 않을 경우엔 as? 를 사용

if-let 구문을 통해 as? 연산자로 다운캐스팅하고 반환된 옵셔널 값을 처리하는 방법 (일반적인 방법)

// 다운캐스팅
// 3개 변수를 가진 항목(person)이
// 5개 변수를 가진 항목(undergraduate)에 접근하려고 함
let person2 = person as? Undergraduate
print(person2) 		//nil

if let newPerson = person as? Undergraduate {
	print("hello newPerson")
}

 

++ Swift 타입과 Objective-C 타입 간은 as를 사용

(내부적으로 완전히 상호 호환이 가능하도록 설계)

~> 여전히 Objective-C 기반의 프레임워크를 사용중이기 때문에 


코딩을 하다보면 어떤 타입으로 반환하거나 제공해야하는 지 헷갈리는 경우가 생김

이런 경우를 위해 스위프트에서는 불특정한 타입을 다룰 수 있는 타입을 제공함

Any

기본 타입(Int, String, Bool,...), 커스텀 클래스, 구조체, 열거형, 함수타입까지도 포함해서

어떤 타입의 인스턴스도 표현할 수 있는 타입 (옵셔널 타입도 포함)

 

var anySomthing: Any = "Swift"
anySomthing = 10
anySomthing = 3.3

 

Any 타입은 옵셔널 타입을 포함한 모든 타입을 나타낼 수 있기 때문에

저장된 타입의 메모리 구조를 알 수 없어서 항상 타입캐스팅을 해야함

let array: [Any] = ["Swift", 5, 4,56, Person()]

for item in array {
	if let item as? String {
    	print(item)
    }
}

 

AnyObject

어떤 클래스 타입의 인스턴스도 표현할 수 있는 타입

let objArray:[AnyObject] = [Person(), Student(), NSString()]

(objArray[0] as! Person).name	//"이름"

 

Any / AnyObject은 switch문에서 is / as 패턴을 사용해서 분기 처리 가능

for (index, item) in array.enumerated() {
    switch item {
    case is Int:                                  // item is Int
        print("Index - \(index): 정수입니다.")
    case let num as Double:                       // let num = item as Double
        print("Index - \(index): 소수 \(num)입니다.")
    case is String:                               // item is String
        print("Index - \(index): 문자열입니다.")
    case let person as Person:                    // let person = item as Person
        print("Index - \(index): 사람입니다.")
        print("이름은 \(person.name)입니다.")
        print("나이는 \(person.age)입니다.")
    case is (String) -> String:                   // item is (String) -> String
        print("Index - \(index): 클로저 타입입니다.")
    default:
        print("Index - \(index): 그 이외의 타입입니다.")
    }
}

의도적인 옵셔널값의 사용

Any는 모든 타입을 포함하므로, 의도적인 옵셔널값을 사용하려면 Any타입으로 변환하면

  컴파일러가 알려주는 경고를 없앨 수 있음

let optionalNumber: Int? = 3
print(optionalNumber)          // 경고
print(optionalNumber as Any)   // 경고 없음

왜 사용할까?

옵셔널값은 임시적인 값일 뿐이므로, 일반적으로 개발자들은

옵셔널 바인딩을 해서 언래핑해서 안의 값을 사용해야함

  (Any로 변환하겠다는 것은 그 자체를 사용하겠다는 의미임 ==> 경고 없음)

 

 

++ Any나 AnyObject로 선언하기 보다 예상되는 타입을 구체적으로 지정하는 것이 더 좋음 


참고자료)

https://onelife2live.tistory.com/9

https://zrr.kr/qNHN

'IOS' 카테고리의 다른 글

Swift) 문법 정리 - 프로토콜  (0) 2022.07.12
Swift) 문법 정리 - 튜플  (0) 2022.07.12
Swift) 문법 정리 - 상속  (0) 2022.07.12
Swift) 문법 정리 - 속성(Property) & 함수(Method)  (0) 2022.07.12
Swift) 문법 정리 - 연산자  (0) 2022.07.12
Comments