타입캐스팅(Type Casting)
- 인스턴스 타입을 검사
- 인스턴스 사용시에 어떤 타입으로 사용할지(속성/메서드) 메모리구조에 대한 힌트를 변경하는 것
- 메모리의 값을 수정하는 것이 아님
- 단순히 해당 타입의 인스턴스인 것처럼 취급하려는 목적
is연산자
- 타입을 체크하는 연산자
- 이항연산자
- 참이면 true, 거짓이면 false 리턴
- 상속관계의 계층에서 포함관계를 생각해보면 쉬움.
- 상속 : 기본적으로 데이터(저장 속성)를 추가하는 관점에서 생각
Person() | --> (true) --> <-- (false) <-- |
Undergraduate() |
[메모리 구조] | [메모리 구조] | |
id | id | |
name | name | |
student id | ||
major |
class Person {
var id = 0
var name = "이름"
var email = "phd0328@gmail.com"
}
class Student: Person {
var studentId = 1
}
class Undergraduate: Student {
var major = "전공"
}
let person1 = Person()
let student1 = Student()
let undergraduate1 = Undergraduate()
// 사람 인스턴스는 학생/대학생 타입은 아니다. (사람 타입이다.)
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
// 활용
let people = [person1, student1, undergraduate1]
var studentNum = 0
for someOne in people {
if someOne is Student {
studentNum += 1
}
}
print(studentNum) // 2
as 연산자
- 인스턴스 타입의 (메모리구조에 대한) 힌트를 변경함
- Upcasting
- 인스턴스 as 타입
- 하위클래스의 메모리구조로 저장된 인스턴스를 상위클래스 타입으로 인식
- 상호 호환가능한 타입도 항상 성공
- Downcasting
- 인스턴스 as? 타입
- 참이면 반환타입은 Optional 타입
- 실패시 nil 반환
- 인스턴스 as! 타입
- 참이면 반환타입은 Optional 타입의 값을 강제 언래핑한 타입
- 실패시 런타임 오류
- 인스턴스 as? 타입
let person: Person = Undergraduate() // 5개의 저장 속성을 찍어내는데, person 변수에는 3개만 담는다.
person.id
person.name
person.email
//person.studentId // Value of type 'Person' has no member 'studentId'
//person.major // Value of type 'Person' has no member 'major'
- 왜 studentId, major는 접근이 안될까?
- person변수에는 Person타입이 들어있다고 인식
- 그래서 접근불가, 접근하고 싶다면 메모리구조에 대한 힌트(타입)를 변경 필요
- 어떻게 접근할 수 있을까?
let ppp = person as? Undergraduate
if let newPerson = person as? Undergraduate { // if let바인딩과 함께 사용 (옵셔널 언래핑)
newPerson.major
print(newPerson.major)
}
// 실제로 인스턴스의 접근 범위를 늘려주는 것 뿐
let person2: Undergraduate = person as! Undergraduate
person2.major
let undergraduate2: Undergraduate = Undergraduate()
let person3 = undergraduate2 as Person // 항상 성공
person3.id
person3.name
- as 연산자의 활용
- 브릿징(Bridging) → 서로 호환되는 형식을 캐스팅해서 쉽게 사용하는 것
- 스위프트에서는 내부적으로 여전히 Objective-C 프레임워크를 사용하는 것이 많기 때문에 서로 완전히 상호 호환이 가능하도록 설계해놓음.
- 타입 캐스팅을 강제할 필요 없음
let str: String = "Hello"
let otherStr = str as NSString
상속과 다형성
- 다형성
- 하나의 객체(인스턴스)가 여러가지의 타입의 형태로 표현될 수 있음.
- (또는 하나의 타입으로 여러 종류의 객체(인스턴스)를 여러가지 형태(모습)으로 해석될 수 있는 성격)
- 다형성은 클래스의 상속(+프로토콜)과 깊은 연관성이 있음
- [상속을 통한 메서드의 재정의와 다형성]
- 하나의 인스턴스는 업캐스팅된 타입(Person)으로 인식되고 호출되더라도 실제 인스턴스 형태(Undergraduate)에 따라 재정의된 메서드가 호출되고 실행
- 타입의 저장 형태는 속성/메서드에 대한 접근가능 범위를 나타내는 것이고, 다형성은 인스턴스에서 메모리의 실제 구현 내용에 대한 것
- 메서드는 재정의 가능하고 메서드 테이블을 통해 동작
let people: [Person] = [Person(), Student(), Undergraduate()]
// 반복문
for person in people {
person.walk()
}
// 한개씩
people[0].walk() // Person 타입으로 인식 (Person 인스턴스)
people[1].walk() // Person 타입으로 인식 (Student 인스턴스)
people[2].walk() // Person 타입으로 인식 (Undergraduate 인스턴스)
Any와 AnyObject
- Any
- 스위프트 기본타입 포함 클래스, 구조체, 열거형, 함수 등 어떤 타입의 인스턴스도 표현할 수 있는 타입
- AnyObject
- 어떤 클래스 타입의 인스턴스도 표현할 수 있는 타입 (정확하게는 AnyObject 프로토콜)
- [참고] → 나중에
- typealias AnyClass = AnyObject.Type
- 장단점
- 단점 → 저장된 타입의 메모리 구조를 알 수없기 때문에, 항상 타입캐스팅해서 사용해야함 ⭐️
- 장점 → 모든 타입을 담을 수 있는 배열을 생성 가능(Any 타입)
- 타입캐스팅 + 분기처리가 가능

var some: Any = "Swift"
(some as! String).count
let array: [Any] = [5, "안녕", 3.5, Person(), Superman(), {(name: String) in return name}]
for (index, item) in array.enumerated() {
// (0, 5)
// (1, "안녕")
// (2, 3.5)
// ...
switch item {
case is Int: // item is Int
print("Index - \(index): 정수입니다.")
case let num as Double: // let num = item as Double, if let 바인딩처럼 성공하는 경우에만 담기기 때문에 ? 생략(as임)
print("Index - \(index): 소수 \(num)입니다.")
case is String: // item is String
print("Index - \(index): 문자열입니다.")
case let person as Person: // let person = item as Person, 바인딩을 진행(as일 때)
print("Index - \(index): 사람입니다.")
print("이름은 \(person.name)입니다.")
print("나이는 \(person.age)입니다.")
case is (String) -> String: // item is (String) -> String
print("Index - \(index): 클로저 타입입니다.")
default:
print("Index - \(index): 그 이외의 타입입니다.")
}
}
- 옵셔널값의 Any 반환
- 의도적인 옵셔널값의 사용
- Any는 모든 타입을 포함하므로, 의도적인 옵셔널값을 사용하려면 Any 타입으로 변환하면 컴파일러가 알려주는 경고를 없앨 수 잇음
- 의도적인 옵셔널값의 사용
let optionalNumber: Int? = 3
print(optionalNumber) // 경고
print(optionalNumber as Any) // 경고 없음
반응형
'iOS > Swift' 카테고리의 다른 글
Swift No.20 (1) | 2024.01.27 |
---|---|
Swift No.19 (1) | 2024.01.25 |
Swift No.17 (1) | 2024.01.23 |
Swift No.16 (0) | 2024.01.17 |
Swift No.15 (0) | 2024.01.17 |
타입캐스팅(Type Casting)
- 인스턴스 타입을 검사
- 인스턴스 사용시에 어떤 타입으로 사용할지(속성/메서드) 메모리구조에 대한 힌트를 변경하는 것
- 메모리의 값을 수정하는 것이 아님
- 단순히 해당 타입의 인스턴스인 것처럼 취급하려는 목적
is연산자
- 타입을 체크하는 연산자
- 이항연산자
- 참이면 true, 거짓이면 false 리턴
- 상속관계의 계층에서 포함관계를 생각해보면 쉬움.
- 상속 : 기본적으로 데이터(저장 속성)를 추가하는 관점에서 생각
Person() | --> (true) --> <-- (false) <-- |
Undergraduate() |
[메모리 구조] | [메모리 구조] | |
id | id | |
name | name | |
student id | ||
major |
class Person {
var id = 0
var name = "이름"
var email = "phd0328@gmail.com"
}
class Student: Person {
var studentId = 1
}
class Undergraduate: Student {
var major = "전공"
}
let person1 = Person()
let student1 = Student()
let undergraduate1 = Undergraduate()
// 사람 인스턴스는 학생/대학생 타입은 아니다. (사람 타입이다.)
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
// 활용
let people = [person1, student1, undergraduate1]
var studentNum = 0
for someOne in people {
if someOne is Student {
studentNum += 1
}
}
print(studentNum) // 2
as 연산자
- 인스턴스 타입의 (메모리구조에 대한) 힌트를 변경함
- Upcasting
- 인스턴스 as 타입
- 하위클래스의 메모리구조로 저장된 인스턴스를 상위클래스 타입으로 인식
- 상호 호환가능한 타입도 항상 성공
- Downcasting
- 인스턴스 as? 타입
- 참이면 반환타입은 Optional 타입
- 실패시 nil 반환
- 인스턴스 as! 타입
- 참이면 반환타입은 Optional 타입의 값을 강제 언래핑한 타입
- 실패시 런타임 오류
- 인스턴스 as? 타입
let person: Person = Undergraduate() // 5개의 저장 속성을 찍어내는데, person 변수에는 3개만 담는다.
person.id
person.name
person.email
//person.studentId // Value of type 'Person' has no member 'studentId'
//person.major // Value of type 'Person' has no member 'major'
- 왜 studentId, major는 접근이 안될까?
- person변수에는 Person타입이 들어있다고 인식
- 그래서 접근불가, 접근하고 싶다면 메모리구조에 대한 힌트(타입)를 변경 필요
- 어떻게 접근할 수 있을까?
let ppp = person as? Undergraduate
if let newPerson = person as? Undergraduate { // if let바인딩과 함께 사용 (옵셔널 언래핑)
newPerson.major
print(newPerson.major)
}
// 실제로 인스턴스의 접근 범위를 늘려주는 것 뿐
let person2: Undergraduate = person as! Undergraduate
person2.major
let undergraduate2: Undergraduate = Undergraduate()
let person3 = undergraduate2 as Person // 항상 성공
person3.id
person3.name
- as 연산자의 활용
- 브릿징(Bridging) → 서로 호환되는 형식을 캐스팅해서 쉽게 사용하는 것
- 스위프트에서는 내부적으로 여전히 Objective-C 프레임워크를 사용하는 것이 많기 때문에 서로 완전히 상호 호환이 가능하도록 설계해놓음.
- 타입 캐스팅을 강제할 필요 없음
let str: String = "Hello"
let otherStr = str as NSString
상속과 다형성
- 다형성
- 하나의 객체(인스턴스)가 여러가지의 타입의 형태로 표현될 수 있음.
- (또는 하나의 타입으로 여러 종류의 객체(인스턴스)를 여러가지 형태(모습)으로 해석될 수 있는 성격)
- 다형성은 클래스의 상속(+프로토콜)과 깊은 연관성이 있음
- [상속을 통한 메서드의 재정의와 다형성]
- 하나의 인스턴스는 업캐스팅된 타입(Person)으로 인식되고 호출되더라도 실제 인스턴스 형태(Undergraduate)에 따라 재정의된 메서드가 호출되고 실행
- 타입의 저장 형태는 속성/메서드에 대한 접근가능 범위를 나타내는 것이고, 다형성은 인스턴스에서 메모리의 실제 구현 내용에 대한 것
- 메서드는 재정의 가능하고 메서드 테이블을 통해 동작
let people: [Person] = [Person(), Student(), Undergraduate()]
// 반복문
for person in people {
person.walk()
}
// 한개씩
people[0].walk() // Person 타입으로 인식 (Person 인스턴스)
people[1].walk() // Person 타입으로 인식 (Student 인스턴스)
people[2].walk() // Person 타입으로 인식 (Undergraduate 인스턴스)
Any와 AnyObject
- Any
- 스위프트 기본타입 포함 클래스, 구조체, 열거형, 함수 등 어떤 타입의 인스턴스도 표현할 수 있는 타입
- AnyObject
- 어떤 클래스 타입의 인스턴스도 표현할 수 있는 타입 (정확하게는 AnyObject 프로토콜)
- [참고] → 나중에
- typealias AnyClass = AnyObject.Type
- 장단점
- 단점 → 저장된 타입의 메모리 구조를 알 수없기 때문에, 항상 타입캐스팅해서 사용해야함 ⭐️
- 장점 → 모든 타입을 담을 수 있는 배열을 생성 가능(Any 타입)
- 타입캐스팅 + 분기처리가 가능

var some: Any = "Swift"
(some as! String).count
let array: [Any] = [5, "안녕", 3.5, Person(), Superman(), {(name: String) in return name}]
for (index, item) in array.enumerated() {
// (0, 5)
// (1, "안녕")
// (2, 3.5)
// ...
switch item {
case is Int: // item is Int
print("Index - \(index): 정수입니다.")
case let num as Double: // let num = item as Double, if let 바인딩처럼 성공하는 경우에만 담기기 때문에 ? 생략(as임)
print("Index - \(index): 소수 \(num)입니다.")
case is String: // item is String
print("Index - \(index): 문자열입니다.")
case let person as Person: // let person = item as Person, 바인딩을 진행(as일 때)
print("Index - \(index): 사람입니다.")
print("이름은 \(person.name)입니다.")
print("나이는 \(person.age)입니다.")
case is (String) -> String: // item is (String) -> String
print("Index - \(index): 클로저 타입입니다.")
default:
print("Index - \(index): 그 이외의 타입입니다.")
}
}
- 옵셔널값의 Any 반환
- 의도적인 옵셔널값의 사용
- Any는 모든 타입을 포함하므로, 의도적인 옵셔널값을 사용하려면 Any 타입으로 변환하면 컴파일러가 알려주는 경고를 없앨 수 잇음
- 의도적인 옵셔널값의 사용
let optionalNumber: Int? = 3
print(optionalNumber) // 경고
print(optionalNumber as Any) // 경고 없음
반응형
'iOS > Swift' 카테고리의 다른 글
Swift No.20 (1) | 2024.01.27 |
---|---|
Swift No.19 (1) | 2024.01.25 |
Swift No.17 (1) | 2024.01.23 |
Swift No.16 (0) | 2024.01.17 |
Swift No.15 (0) | 2024.01.17 |