스위프트 문법 16 (Type Casting, Any Type)

스위프트 문법 16 (Type Casting, Any Type)

- 8 mins

Type Casting

모든 프로그래밍 언어들이 그렇듯 Swift에는 다양한 종류의 Type가 존재하고, 질서 유지를 위해 다른 종류의 Type들을 섞어서 사용할 수 없다. 그렇기 때문에 서로 다른 Type을 섞어 사용하기위해서는 Type Casting이 필요하다.

Type Check

아래와 같은 여러가지 변수의 타입을 알아내는 방법을 설명하도록 하겠다.

class className {}
var anyArray: [Any] = [1, "2", 3.0]
var anyObjectArray: [AnyObject] = [className()]

타입 확인 - type(of: )

type(of: )라는 함수를 이용하면 간단하게 확인할 수 있다.

func printGenericInfo<T>(_ value: T) {    //여기서 파라미터 T는 타입을 알려주는 타입이다.
  let types = type(of: value)
  print("'\(value)' of type '\(types)'")
}
printGenericInfo(2)   //'2' of type 'Int'

type(of: anyArray)        //type(of: anyArray)
type(of: anyObjectArray)  //type(of: anyObjectArray)
type(of: 1)               //type(of: 1)

타입 비교 - is

두가지의 타입을 비교할때는 is를 이용해 간단하게 비교할 수 있다.

var anyArray: [Any] = [1, "2", 3.0]
if anyArray[0] is Int {
  print("Int")        //Int
} else {
  print("else")
}

type(of: anyArray[0])   //Int.Type

위에서 배운 타입 확인에 사용한 type(of: )를 사용하기 위해서는 .Type까지 명시해줘야 한다.

if type(of:anyArray[0]) is Int.Type {
  print("Equal")
}

if type(of:anyArray[0]) is Int {  //에러 발생
  print("Equal")
}

또, 아래와 같이 witch문을 이용해서 찾을 수 있다.

var anyArray: [Any] = [1, "2", 3.0]
for i in 0...anyArray.count-1 {
    switch anyArray[i] {
    case is Int:
        print("Int")
    case is String:
        print("String")
    case is Double:
        print("Double")
    default:
        print("?")
    }
}

/* 출력 값
Int
String
Double
*/

상속 관계

상속 관계일때 is를 이용해 부모 클래스인지, 자식 클래스인지 알 수 있다.

class Human {}
class Student: Human {}
class Baby: Human {}

let someone: Student = Student()
print(someone is Human)     //true
print(someone is Student)   //true
print(someone is Baby)      //false

위 예제에서 someone은 Student이기때문에 Human을 상속받았지만, Baby를 상속받지는 않았다. 그렇기 때문에 is Human, is Student에는 true를 return하지만 is Baby는 false를 return한다.


Type Casting

  1. as : 타입 변환이 확실하게 가능한 경우(업캐스팅, 자기 자신 등) 에만 사용 가능. 그 외에는 컴파일 에러
  2. as? : 강제 타입 변환 시도. 변환이 성공하면 Optional 값을 가지며, 실패 시에는 nil 반환
  3. as! : 강제 타입 변환 시도. 성공 시 언래핑 된 값을 가지며, 실패 시 런타임 에러 발생

Type Casting에 사용될 클래스들 선언

import UIKit

class Shape {
    var color = UIColor.white
    
    func draw() {
        print("draw shape")
    }
}

class Rectangle: Shape {
    var cornerRadius = 0.0
    
    override func draw() {
        print("draw rect")
    }
}

class Triangle: Shape {
    override func draw() {
        print("draw triangle")
    }
}

class Circle: Shape {
    var radius = 50.0
    
    override func draw() {
        print("draw circle")
    }
}

let shape = Shape()
let rectangle = Rectangle()
let triangle = Triangle()
let circle = Circle()

Upcasting

자기보다 부모 클래스를 사용해서 업캐스팅하여 선언 사실상 거의 사용되지 않는다.

let rect = Rectangle()      //일반적인 Rectangle
rect.color          //사용 가능 
rect.cornerRadius   //사용 가능

let upcastedRect: Shape = Rectangle()   //Shape를 사용한 Rectangle
upcastedRect.color  //사용 가능
//upcastedRect.cornerRadius   //사용 불가

Downcasting

아래와 같이 사용하면 오류남. 이유는 Rectangle은 Shape의 자식 클래스이기 때문에

let downcastedRect: Rectangle = upcastedRect 

다운사이징 후 사용하기 위해서는 아래와 같이 as를 이용해 형변환을 해줘야한다.

let upcastedRect: Shape = Rectangle()

let downcastedRect: Rectangle = upcastedRect as! Rectangle
downcastedRect.color
downcastedRect.cornerRadius

아래와 같이 as?를 이용해서도 가능하다

if let downcastedRect = upcastedRect as? Rectangle {
    print(downcastedRect)
}

Type Check Operator

let list = [shape, rectangle, triangle, circle]     //타입은 [shape]이다.

for elem in list {
    if elem is Shape {         // always true
        print("shape instance")
    } else if elem is Rectangle {
        print("rect instance")
    } else if elem is Triangle {
        print("triangle instance")
    } else if elem is Circle {
        print("circle instance")
    }
}

업, 다운 캐스팅 정리

업 캐스팅

다운 캐스팅


Any , AnyObject

일반적(Int, String등)인 변수 선언에서 타입을 지정하게 되는데 그 외의 다른 타입은 넣을 수 없다. 하지만 Any를 이용한다면 모든 타입을 넣을 수 있다.
Any(모든 타입), AnyObject(모든 레퍼런스 타입: class) Any > AnyObject

class SomeClass1 {}
class SomeClass2 {}

var anyArray: [Any] //Any타입을 사용할때는 항상 명시해줘야한다.
var anyObjectArray: [AnyObject]

anyArray = [0, "str", true, 9.9, SomeClass1()]  //모든 일반적인 타입을 다 넣음
//아래에는 일반적인 타입을 넣으면 오류가 난다. 오직 레퍼런스 타입만을 넣을 수 있다.
anyObjectArray = [SomeClass1(), SomeClass2(), SomeClass1(), SomeClass2()] 

anyArray.append("newElement") //추가도 가능하다.

하지만 값을 가져와 추가를 하려면 아래와 같이 형변환을 해줘야 한다.

var num2: Int = (anyArray[0] as? Int)!
var num3: Int! = anyArray[0] as? Int
var num4: Int = anyArray[0] as! Int
type(of: anyArray[0])   // Int.Type
type(of: anyArray[1])   // String.Type
anyArray[0]             //0
anyArray[1]             //"str"

print(anyArray[1])      //str
print(type(of: anyArray[1]))  //String
comments powered by Disqus
rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora