[Swift 프로그래밍] 타입캐스팅 (TypeCasting)

이정훈·2022년 6월 29일
1

Swift 기본

목록 보기
18/22
post-thumbnail

본 내용은 스위프트 프로그래밍 3판 (야곰 지음) 교재를 공부한 내용을 바탕으로 작성 하였습니다.

Swift의 타입캐스팅


아래는 String 타입을 Int 타입으로 형 변화하는 코드이다.

var stringValue: String = "123"
var integerValue: Int = Int(stringValue)

사실 위의 코드는 String 타입의 stringValue 변수를 Int 타입으로 변환해 주는것 처럼 보이지만, 사실 스위프트에서 이러한 과정은 Int타입의 구조체의 인스턴스를 생성하는 과정과 같다.

스위프트에서 타입캐스팅은 약간 다른 형태로 구현 되어 있는데, 스위프트에서 타입캐스팅은 인스턴스의 타입을 확인하거나 자신의 타입을 상위 클래스 타입으로 변환하는 식으로 사용이 가능하며, is 연산자와 as 연산자로 구현할 수 있다.

아래의 코드는 Music 클래스를 상속 받는 Classic 클래스와 Pop 클래스를 구현하였다.

class Music {
    let name: String
    
    var play: String {
        return "\(name)(이)가 재생중입니다."
    }
    
    init(name: String) {
        self.name = name
    }
}

class Classic: Music {
    let instrument: String
    
    override var play: String {
        return "\(instrument)\(name)을 연주중 입니다."
    }
    
    init(name: String, instrument: String) {
        self.instrument = instrument
        super.init(name: name)
    }
}

class Pop: Music {
    let singer: String
    
    override var play: String {
        return "\(singer)\(name)을 노래중 입니다."
    }
    
    init(name: String, singer: String) {
        self.singer = singer
        super.init(name: name)
    }
}

데이터 타입 확인


위에서 설명했듯이 데이터 타입을 확인하기 위하여 is 연산자를 사용하여 인스턴스가 어떤 클래스의 인스턴스인지(또는 어떤 클래스의 자식 클래스 인스턴스인지) 확인 가능하다.

또한 is 연산자의 타입 확인 결과는 Bool 타입으로 참이면 true를 틀리면 false를 반환한다.

let music: Music = Music(name: "한국 노래")
let myClassic: Classic = Classic(name: "체르니", instrument: "피아노")
let yourPop: Pop = Pop(name: "강남 스타일", singer: "psy")

print(music.play)
print(myClassic.play)
print(yourPop.play)

//타입 확인
print(music is Music)   	//true
print(myClassic is Music)   //true
print(yourPop is Music)     //true

print(music is Classic)     //false
print(myClassic is Classic) //true
print(yourPop is Classic)   //false

print(music is Pop)     //false
print(myClassic is Pop) //false
print(yourPop is Pop)   //true

ClassicPop은 모두 Music클래스의 자식 클래스 이기 때문에 Classic과 Pop으로 선언된 상수들은 Music 클래스와의 타입 확인에서 모두 true가 반환되는 것을 확인할 수 있다.

또한 Music 클래스는 ClassicPop의 부모 클래스 이기 때문에 Classic 또는 Pop과의 타입 확인에서 모두 false를 반환한다. (Classic과 Pop이 Music이 될수 있지만 Music이 Classic과 Pop이 될수는 없기 때문)

다운 캐스팅 (Down Casting)


위에서 확인한 바와 같이 Pop 클래스는 Music 클래스의 상속을 받아 상수 yourPopPop 클래스이면서, Music클래스 임을 확인 할수 있다.

따라서 다음과 같이 클래스 형 변환이 일어날 수 있다. (역은 성립하지 않음)

let yourPop: Music = Pop(name: "강남 스타일", singer: "psy")

이럴경우, Pop 타입에만 존재하는 메서드나 프로퍼티를 사용하기 위해서는 상수를 Pop 클래스로 다운캐스팅 해주어야 한다.

다운캐스팅을 구현하기 위해서 as? 연산자와 as! 연산자를 사용한다.

  • as? 연산자는 다운캐스팅 실패를 내포하며 다운캐스팅 실패시 nil을 반환한다. 반대로 다운캐스팅에 성공하면 옵셔널 타입으로 반환한다.

  • as! 연산자는 강제로 다운캐스팅을 실시하며 실패시 런타임 에러를 발생시킨다.

다음은 다운캐스팅을 구현한 코드이다.

if let test: Classic = music as? Classic {
    print("Classic 타입으로 캐스팅 가능합니다.")
}
else {
    print("Classic 타입으로 캐스팅 불가능합니다.")
}

if let test: Classic = myClassic as? Classic {
    print("Classic 타입으로 캐스팅 가능합니다.")
}
else {
    print("Classic 타입으로 캐스팅 불가능합니다.")
}

if let test: Classic = yourPop as? Classic {
    print("Classic 타입으로 캐스팅 가능합니다.")
}
else {
    print("Classic 타입으로 캐스팅 불가능합니다.")
}

//강제 타입캐스팅
let test: Music = music as! Music

형태가 마치 옵셔널 바인딩을 구현하는 것과 같이 비슷한데,
첫번째 코드를 살펴보면 Classic 클래스로 선언된 상수 testmusic 상수를 Classic 클래스로 타입 캐스팅하여 할당 가능한지에 대하여 true이면 if문의 수행문을 fasle이면 else문의 수행문을 수행하도록 구현하였다.

그리고 마지막 코드는 강제 타입 캐스팅을 구현하였는데 일단 강제로 타입 캐스팅을 시도하고 만약 불가능한 경우 런타임 에러를 발생시킨다.

Any, AnyObject 타입 캐스팅


위에서 타입 캐스팅을 구현할 때 직접 타입 이름을 지정해 줬는데 스위프트에는 여러 타입을 할당 가능한 Any 타입과 AnyObject가 존재한다.

  • Any 타입은 함수 타입을 포함한 모든 타입을 말한다.

  • AnyObject는 클래스 타입만을 말한다.

Any 타입과 AnyObject 타입의 장점이라면 어떤 타입이라도 할당 받아 사용이 가능하지만 반대로 단점은 전달된 타입이 어떤 타입인지 정확히 확인하는 과정을 거쳐야 된다는 것이다.

다음은 AnyObject 타입으로 타입을 전달 받고 확인 후 타입 캐스팅까지 구현한 코드이다.

func typecastingOfAnyObject(object: AnyObject) -> Void {
    if let test: Pop = object as? Pop {
        print("Pop 음악입니다.")
    } else if let test: Classic = object as? Classic {
        print("Classic 음악입니다.")
    } else if let test: Music = object as? Music {
        print("음악입니다.")
    } else {
        print("알 수 없는 음악입니다.")
    }
}

typecastingOfAnyObject(object: music)
typecastingOfAnyObject(object: myClassic)
typecastingOfAnyObject(object: yourPop)

다음은 Any 타입으로 타입을 전달 받고 확인 후 타입 캐스팅까지 구현한 코드이다.

//Any 타입캐스팅
func checkAny(of object: Any) -> Void {
    if let test: Music = object as? Music {
        print("음악 입니다.")
    } else if let number: Int = object as? Int {
        print(number)
    } else if let string: String = object as? String {
        print("\(string)")
    } else if let stringToString: (String) -> String = object as? (String) -> String {
        print(stringToString("Hello"))
    } else {
        print("Unkown type")
    }
}

checkAny(of: myClassic)
checkAny(of: 123)
checkAny(of: "안녕하세요!")
checkAny(of: { (greet: String) -> String in "\(greet)! nice to meet you"})

Any 타입은 클래스 타입부터 Int, String 타입(외에도 Double, 컬렉션 형 등)과 심지어 함수까지 전달 받을 수 있다.

profile
새롭게 알게된 것을 기록하는 공간

0개의 댓글