Swift Casting as! as? as 총 정리
Swift의 Casting에 대해서 알아보겠다.
class Animal {
var name: String
init(n: String) {
name = n
}
}
class Human: Animal {
func code() {
print("Typing away...")
}
}
class Fish: Animal {
func breatheUnderWater() {
print("Breathing under water.")
}
}
3개의 Class가 있다.
Animal은 이름을 가지고 있고 새로운 animal을 만들 때, 이름을 초기화 한다.
Human, Fish는 Animal의 Sub Class이다.
let jack = Human(n: "Jack Lee")
let bob = Human(n: "Bob Bauer")
let nemo = Fish(n: "Nemo")
let neighbours = [jack, bob, nemo]
neighbours이라는 array로 class가 다른 Human과 Fish를 함께 넣었는데, 이게 가능하다.
왜냐하면 Animal이라는 Super Class가 같기 때문이다.
neighbours는 Animal Object가 된다.
let neighbour1 = neighbours[0]
neighbours의 0 index는 Human인데 neighbour1 역시 Animal Object가 된다.
if neighbours[0] is Human {
print("First Neighbour is a Human")
}
이것을 돌리면 어떻게 될까?
First Neighbour is a Human가 print 되어 나온다.
왜냐하면 neighbours[0]은 jack으로 대처되기 때문이다.
그러나 neightbours[2]는 안된다.
is 키워드는 Type Checking에 사용된다.
func findNemo(from animals: [Animal]) {
for animal in animals {
if animal is Fish {
print(animal.name)
animal.breatheUnderWater() // error
}
}
}
findNemo(from: neighbours)
결과값은 Nemo만 나오는데, for loop에서 모든 animal을 check하지만 Fish에 match되는 data만 찾기 때문이다.
그러나 animal.breatheUnderWater() 에러가 뜬다.
왜냐하면 여전히 Animal 타입을 가지기 때문이다.
이럴때 down casting을 해줘야한다 (Super -> Sub)
as! 을 이용한다.
func findNemo(from animals: [Animal]) {
for animal in animals {
if animal is Fish {
let fish = animal as! Fish
fish.breatheUnderWater() // 정상적으로 됨!
}
}
}
findNemo(from: neighbours)
let fish = neighbours[1] as! Fish
이것을 쓰면 어떻게 될까? -> Crash
Human을 casting을 시도해도 Fish로 되지 않는다.
이럴 땐 as? 을 사용한다.
let fish = neighbours[1] as? Fish {
fish?.breatheUnderWater()
} else {
print("Casting has failed")
}
이렇게 쓰게 되면 crash가 일어나지 않고 해당되지 않으니 Casting has failed이 출력된다.
그래서 as? 을 사용하면 crash를 방지하며 안전하게 가능하다.
확실하게 모르는 경우, as?를 사용하면 좋을것 같다.
그렇다면 반대로 casting 하려면 어떻게 해야할까?
func findNemo(from animals: [Animal]) {
for animal in animals {
if animal is Fish {
let animalFish = fish as Animal
}
}
}
as 만 적어주면 된다.
Upcast는 항상 crash이 없이 정상적으로 동작 된다.
swift에서 대표적으로 사용되는 data type에서 구조를 보면
Any > AnyObject > NSObject 순으로 super class에 해당된다.
let jack = Human(n: "Jack Lee")
let bob = Human(n: "Bob Bauer")
let nemo = Fish(n: "Nemo")
let num = 12
let neighbours: [Any] = [jack, bob, nemo, num]
다시 여기서 숫자를 넣으려면 어떻게 할까?
Any를 사용하면 된다.
Any는 여러 클래스나 구조체 또는 다른 데이터 타입도 모두 허용한다.
let neighbours: [AnyObject] = [jack, bob, nemo, num]
AnyObject를 쓰면 어떻게 될까?
Error가 뜬다.
AnyObject는 Class에서 받아오는 타입에 대한 제한이 있다.
그보다 낮은 NSObject도 당연히 안된다.
let num: NSNumber = 12
let word: NSString = "ABC"
let neighbours: [NSObject] = [num, word]
그러나 이거는 잘 된다.
둘 다 특정한 요구에 맞는 NSObjects이기 때문이다.
댓글남기기