Weekly Sesac: Any와 TypeCasting
지난번에도 한번 작성한 내용이지만 왜 type casting이 필요할까에 대해 다뤄보려 한다.
Type Casting
Determine a value’s runtime type and give it more specific type information.
Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy.
instance의 type을 체크하거나, 혹은 생성된 타입과 다른 클래스인것처럼 다루는 것을 의미한다.
SuperClass와 SubClass instance 관계는 다음과 같다.
SubClass의 instance는 SuperClass type으로도 활용이 가능하다. SubClass는 SuperClass의 특성을 상속받았기 때문.
반면 SuperClass의 instance는 SubClass type으로 인식하지 않는다. SuperClass에는 SubClass의 property들이 다 존재하지 않기 때문.
이는 마치 집합 개념과 유사하다.
UIKit의 상속 관계를 집합처럼 나타내면 다음과 같이 나타낼 수 있다.
이를 SuperClass와 SubClass 맥락으로 본다면 다음처럼 표현할 수 있다.
let backView = UIView()
let pushButton = UIButton()
UIView
의 instance인 backView는 UIView
의 property를 모두 가지고 있다. UIButton
의 instance인 pushButton은 UIButton
의 property를 모두 가지고 있다.UIButton
은 UIView
와 UIControl
class를 상속받으므로 UIControl
의 property와 UIView
의 property를 모두 가지고 있다.따라서 backView instance를 UIButton
type으로 downcasting해 활용하는 것은 불가능하다. 애초에 backView instance는 UIButton
의 property를 가지고 있지 않기 때문이다.
하지만 pushButton은 UIView
의 property를 모두 가지고 있으므로, UIView
type이라고 인식해도 무방하다.
개발자 자신은 그렇게 쓰기 싫겠지만 함수 메서드를 활용하다보면 일반적인 타입으로 return하기 위해 상위 class로 인식되는 경우가 존재한다.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ExampleCollectionViewCell", for: indexPath) as! ExampleCollectionViewCell
// Configure the cell
let data = dataList[indexPath.row]
cell.configCell(data: data)
return cell
}
as 없이 재사용 cell을 정의하면 type이 UICollectionViewCell
이다.
이 상태로 cell을 return해도 컴파일 에러는 나타나지 않는다.
하지만 ExampleCollectionViewCell
type의 method와 property에 접근하기 위해선 UICollectionViewCell
을 상속받은 ExampleCollectionViewCell
로 downcasting 해야 한다.
downcasting 없이 configCell
method에 접근하면 존재하지 않는 요소라고 컴파일 에러를 일으킨다.
UICollectionView
에서 해당 cell을 눌렀을 때, DetailViewController
로 화면 전환되는 코드이다.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let detailVC = storyboard.instantiateViewController(withIdentifier: DetailViewController.identifier)
detailVC.title = dataList[indexPath.row].title
navigationController?.pushViewController(detailVC, animated: true)
}
이 코드에서는 cell에서 화면 전환 시, 해당 ViewController의 NavigationBar의 title 설정만 존재하고, 데이터를 넘겨주지 않기 때문에 detailVC가 downcasting없이 UIViewController
로 활용되어도 컴파일 에러가 나타나지 않는다.
하지만 만약 detailVC의 label이나 imageView에 관련 정보를 넘겨주기 위해 접근하는 코드가 있었다면 컴파일 에러가 발생했을 것이다.
type casting 그 자체로는 큰 문제가 없다. 해당 class의 instance의 property에 접근 권한이 있어야하기 때문에 상속받는 downcasting이 필요한 것이다.
이는 class가 메모리에 올라오는 구조와도 연관이 있는데 이는 메모리를 본격적으로 다룰 때 다시 정리하기로 하고 간단하게 정리하면 다음과 같다.