상속 : 기본적으로 저장속성을 추가하는 관점에서 생각
class Person {
var id = 0
var name = "이름"
var email = "abc@gmail.com"
}
class Student: Person {
// id, name, email
var studentId = 1
}
class Undergraduate: Student {
// id, name, email, studentId
var major = "전공"
}
사람 인스턴스는 학생/대학생 타입은 아니다. (사람 타입이다.)
person1 is Person // true
person1 is Student // false
person1 is Undergraduate // false
학생 인스턴스는 대학생 타입은 아니다. (사람/학생 타입니다.)
student1 is Person // true
student1 is Student // true
student1 is Undergraduate // false
대학생 인스턴스는 사람이거나, 학생이거나, 대학생 타입 모두에 해당한다.
undergraduate1 is Person // true
undergraduate1 is Student // true
undergraduate1 is Undergraduate // true
💡 is 연산자는 포함관계를 생각하면 편하다 ”왼쪽 is 오른쪽”이라면 왼쪽이 오른쪽을 포함할수있니를 물어본다고 생각예를들어서 Person타입으로 선언한 변수에 Undergraduate인스턴스를 담는다면
let person: Person = Undergraduate()
Undergrauate인스턴스는 id, name, email, studentId, major를 모두 가지고 있지만
person변수에는 Person이 들어있다고 인지를 하기 때문에(Person형식의 박스)
✅studentId와 major변수에는 접근이 불가능하다✅
let ppp = person as? Undergraduate
ppp라는 변수에 person이라는 변수의 타입을 Undergraduate로 바꿔서 저장
(optional Undergraduate타입이기때문에 옵셔널 바인딩이 필요하다)
// if let 바인딩과 함께 사용 (옵셔널 언래핑)
if let newPerson = person as? Undergraduate {
newPerson.major
print(newPerson.major)
}
// 실제로 인스턴스의 접근 범위를 늘려주는 것 뿐임
let person3: Undergraduate = person as! Undergraduate
person3.major
언래핑이 가능한걸보니 person(실제로는 Person타입)의 타입을 변환시키는데 성공
let person: Person = Undergraduate()
변수를 선언할때 Undergraduate인스턴스를 생성하기 때문에 저장속성이 5개로 메모리에 올라가게된다
하지만 실제로는 3개만 보이도록(Person타입으로 담는다) 되어있다
💡 as? → 언래핑 해줘야함, as! → 강제 언래핑됨(nil이면 오류 발생)let person: Person = Person()
let ppp = person as? Undergraduate
// 위와같은 방식은 nil을 반환하게 된다 처음부터 3개의 저장속성을 가지고 있는데
// Undergraduate로 다운캐스팅은 불가능하다
// 이런게 가능하다는 의미
let person: Person = Undergraduate()
var some: Any = "Swift"
(some as! String).count
some = 10
some = 3.2
// 단점
// 저장된 타입의 메모리 구조를 알 수없기 때문에, 항상 타입캐스팅해서 사용해야함
====> 업캐스팅(as)
====> 다운캐스팅(as!,?)
💡 그냥 편안하게 Any가 범위가 작은거라고 거꾸로 생각하면 마음이 편하다let objArray: [AnyObject] = [Person(), Superman(), NSString()]
//objArray[0].name 는 접근이 불가능하다 AnyObject니까 무조건 타입캐스팅
(objArray[0] as! Person).name
// AnyObject는 범위가 작은거(아니지만 내가 외우는방법)니까 Person으로 다운캐스팅
// 타입캐스팅 + 분기처리
for (index, item) in array.enumerated() {
// (0, 5)
// (1, "안녕")
// (2, 3.5)
// ...
switch item {
// item is Int
case is Int:
print("Index - \(index): 정수입니다.")
// let num = item as Double
case let num as Double:
print("Index - \(index): 소수 \(num)입니다.")
// item is String
case is String:
print("Index - \(index): 문자열입니다.")
// let person = item as Person
case let person as Person:
print("Index - \(index): 사람입니다.")
print("이름은 \(person.name)입니다.")
print("나이는 \(person.age)입니다.")
// item is (String) -> String
case is (String) -> String:
print("Index - \(index): 클로저 타입입니다.")
default:
print("Index - \(index): 그 이외의 타입입니다.")
}
}
switch item {
case is Int :
print("정수")
// let num = item as! Double
case let num as Double :
print("\(num)")
default :
print("그외의 타입")
}
let optionalNumber: Int? = 3
print(optionalNumber) // 노란색 경고
print(optionalNumber as Any) // 노란색 경고 없음