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이기 때문이다.

태그:

카테고리:

업데이트:

댓글남기기