티스토리 뷰
programming/Swift
[Swift/iOS] 타입캐스팅(2) - 다운캐스팅, as! 와 as?, Any 타입캐스팅, AnyObject 타입캐스팅
마들브라더 2022. 9. 9. 12:22https://modelinspring.tistory.com/61
[Swift/iOS] 타입캐스팅(1) - 타입 변환, 타입캐스팅, 데이터 타입 확인, 메타 타입, 메타 타입 타입
스위프트는 데이터 타입 안전을 위해서 서로 다른 타입끼리의 값 교환을 제한함 1. 기존 언어의 타입 변환과 스위프트 타입 변환 실패할 수 있는 이니셜라이져 // 실패 할 수 있는 이니셜라이져 v
modelinspring.tistory.com
에 이어서 작성되었습니다
스위프트는
- 데이터 타입 안전을 위해서 서로 다른 타입끼리의 값 교환을 제한함
1. 기존 언어의 타입 변환과 스위프트 타입 변환
- 실패할 수 있는 이니셜라이져
// 실패 할 수 있는 이니셜라이져
var string:Value String = "000111222"
var integerValue: Int? = Int(stringValue)
print(integerValue) // Optional(111222)
stringValue = "AAA000111"
integerValue = Int(stringValue)
print(integerValue) // nil
2. 스위프트 타입캐스팅
- 스위프트의 타입캐스팅은 인스턴스의 타입을 확인하거나 자신을 다른 타입의 인스턴스인양 행세할 수 있는 방법
- is와 as로 타입을 확인하거나 다른 타입으로 전환(cast)할 수 있음
- 프로토콜 준수 여부 확인 가능
class Car {
let name: String
let door: Int
var description: String {
return "\\(name) is \\(String(door))door car"
}
init(door:Int) {
self.name = "Car"
self.door = door
}
}
class Z4: Car {
var price: Int
override var description: String {
return "\\(name) has \\(String(door)) door and price is \\(String(price))만원"
}
init(door: Int, price: Int) {
self.price = price
super.init(door: door)
}
}
class EV6: Car {
var speed: String
override var description: String {
return "\\(name) has \\(String(door)) door and \\(speed) speed"
}
init(door: Int, speed: String) {
self.speed = speed
super.init(door: door)
}
}
- Z4 와 EV6는 Car 클래스를 상속
- Car의 프로퍼티를 Z4와 EV6가 가지고 있음
- Car는 Z4나 EV6인 척 할 수 없지만, Z4와 EV6는 Car인 척 할 수 있음 → Z4와 EV6는 Car의 모든 특성을 가지고 있기 때문
3. 데이터 타입 확인
- is를 사용하여 인스턴스가 어떤 클래스의 인스턴스인지 타입을 확인할 수 있음
- 인스턴스가 해당 클래스의 인스턴스거나 그 자식클래스의 인스턴스면 true, 그렇지 않으면 false 반환
let car: Car = Car(door: 5)
print(car.description) // Car is 5 door car
let myZ4: Z4 = Z4(door: 2, price: 8000)
print(myZ4.description) // Car has 2 door and price is 8000만원
let yourEV6 : EV6 = EV6(door: 5, speed: "fast")
print(yourEV6.description) // Car has 5 door and fast speed
print(car is Car) // true
print(car is Z4) // false
print(car is EV6) //false
print(myZ4 is Car) // true
print(yourEV6 is Car) // true
print(myZ4 is EV6) // false
print(yourEV6 is EV6) // true
- car는 Z4나 EV6가 될 수 없지만, myZ4나 yourEV6는 Car가 될 수 있음
- myZ4와 yourEV6는 서로 다른 타입
메타 타입(Meta Type) 타입
- 타입의 타입
- 클래스, 구조체, 열거형 타입 등 타입의 타입
- ‘타입 그 자체'가 하나의 타입으로 또 표현될 수 있음
- 타입의 이름 뒤에 .Tpye을 붙이면 메타 타입
- 프로토콜 타입의 메타 타입은 .Protocol
- .self를 사용하면 타입을 값으로 표현할 수 있음
- SomeClass.self 표현하면 SomeClass의 인스턴스가 아닌 SomeClass를 값으로 표현한 값을 반환
- SomProtocol.self이라고 표현하면 SomeProtocol을 준수하는 타입의 인스턴스가 아닌 SomeProtocol 프로토콜을 값으로 표현한 값 반환
protocol SomeProtocol { }
class SomeClass: SomeProtocol { }
let intType: Int.Type = Int.self
let stringType: String.Type = String.self
let classType: SomeClass.Type = SomeClass.self
let protocolProtocol: SomeProtocol.Protocol = SomeProtocol.self
var someType: Any.Type
someType = intType
print(someType) // Int
someType = stringType
print(someType) // String
someType = classType
print(someType) // SomeClass
someType = protocolProtocol // SomeProtocol
print(someType)
- 인스턴스 self와 타입 self
- .self 표현은 값 뒤에 써주면 그 값 자신을 반환
- 타입 이름 뒤에 써주면 타입을 표현하는 값을 반환
- “stringValue”.self 는 “stringValue”를, String.self는 String 타입 그 자체
print(type(of:car) == Car.self)// true print(type(of:car) == Z4.self) // false print(type(of:car) == EV6.self) // false print(type(of:car) == Z4.self) // false print(type(of:myZ4) == Z4.self) // true print(type(of:yourEV6) == Z4.self) // false print(type(of:car) == EV6.self) // false print(type(of:myZ4) == EV6.self) // false print(type(of:yourEV6) == EV6.self) // true
4. 다운캐스팅
- 어떤 클래스 타입의 변수나 상수가 해당 클래스의 인스턴스가 아닌 다른 클래스의 인스턴스인 것 처럼 사용될 수 있음
//EV6 타입의 인스턴스를 참조하는 Car 타입의 actingConstant
let actionConstant: Car = EV6(door: 5, speed: "fast")
print(actionConstant.description) // Car has 5 door and fast speed
- actingConstant는 실제로는 EV6타입이지만, Car타입인 것처럼 사용될 수 있도록 선언되었음
- 본래의 인스턴스인 EV6로 접근해야할 때는 EV6타입으로 타입변환을 해주어야 함
- == 다운캐스팅
- 부모클래스를 자식클래스타입으로 캐스팅하는 것(down)
- Car 클래스를 자식 클래스인 EV6 타입으로 캐스팅 하는 것
- 클래스의 인스턴스에만 사용하는 것은 아니고, Any 타입에서 다르 타입으로 캐스팅 할때도 이용함
타입캐스트 연산자 as! 와 as?
- 타입캐스트 연산자를 사용하여 자식클래스 타입으로 사용할 수 있음
- 다운캐스팅은 실패할 수 있으므로 as? 연산자는 다운캐스팅이 실패했을 때 nil을 반환함
- as! 연산자는 다운캐스팅에 실패할 경우 런타임 오류 발생
- as?는 반환타입이 옵셔널이고, as!는 아님
- 다운캐스팅이 실패할 가능성이 있다면 조건부 연산자 as?를 사용해야 함
- 성공할 경우, 옵셔널 타입의 인스턴스를 반환
- 실패할 경우, nil 반환
- 다운캐스팅이 무조건 성공하는 상황이면, 강제연산자인 as!를 사용할 수 있음
- 다운캐스팅이 성공할 경우, 옵셔널이 아닌 인스턴스를 반환
- 실패할 경우, 런타임 오류 발생….
//다운캐스팅
if let actionOne: Z4 = car as? Z4 {
print("This car is Z4")
} else {
print(car.description)
} // Car is 5door car
if let actionTwo: EV6 = car as? EV6 {
print("This car is EV6")
} else {
print(car.description)
} // Car is 5door car
if let actionThree: Car = car as? Car {
print("This car is Just Car")
} else {
print(car.description)
} // This car is Just Car
if let actionFour: Z4 = z4 as? Z4 {
print("This car is Z4")
} else {
print(car.description)
} // This car is Z4
if let actionFive: EV6 = z4 as? EV6 {
print("This car is EV6")
} else {
print(car.description)
} // Car is 5door car
if let actionSix: Car = car as? Car {
print("This car is Just Car")
} else {
print(car.description)
} // This car is Just Car
let castedCar: Car = z4 as! Car // Success
let castedZ4: Z4 = car as! Z4 // Runtime Error
- 항상 성공하는 다운캐스팅
let castedCar: Car = ev6 as Car // 컴파일러도 항상 성공한다는 것을 알고 있음
5. Any, AnyObject의 타입캐스팅
- Any와 AnyObject는 특정 타입을 지정하지 않고 여러 타입의 값을 할당할 수 있음
- Any는 모든 함수 타입을 포함한 모든 타입
- AnyObject는 클래스 타입만 뜻함
- Any와 AnyObject는 오류발생확률이 높으니 사용을 지양
- 어떤 타입의 인스턴스인지 체크해보기
func checkType(of item:AnyObject) {
if item is EV6 {
print("Item is EV6")
} else if item is Z4 {
print("Item is Z4")
} else if item is Car {
print("Item is Car")
} else {
print("Unknown Type")
}
}
checkType(of: car) // Item is Car
checkType(of: z4) // Item is Z4
checkType(of: ev6) // Item is EV6
checkType(of: actionConstant) // EV6
- 어떤 타입인지 체크하고 사용할 수 있도록 캐스팅
print("checkType")
func checkType(of item:AnyObject) {
if item is EV6 {
print("Item is EV6")
} else if item is Z4 {
print("Item is Z4")
} else if item is Car {
print("Item is Car")
} else {
print("Unknown Type")
}
}
checkType(of: car) // Item is Car
checkType(of: z4) // Item is Z4
checkType(of: ev6) // Item is EV6
checkType(of: actionConstant) // EV6
func castTypeToAppropriate(item: AnyObject) {
if let castedItem: EV6 = item as? EV6 {
print(castedItem.description)
} else if let castedItem: Z4 = item as? Z4 {
print(castedItem.description)
} else if let castedItem: Car = item as? Car {
print(castedItem.description)
} else {
print("Unknown Type")
}
}
castTypeToAppropriate(item: car) // Car is 5door car
castTypeToAppropriate(item: z4) // Car has 2 door and price is 8000만원
castTypeToAppropriate(item: ev6) // Car has 5 door and fast speed
castTypeToAppropriate(item: actionConstant) // Car has 5 door anvd fast speed
- AnyObject와 달리 모든 클래스의 인스턴스를 취할 수 있는 Any
func checkAnyType(of item: Any) {
switch item {
case 0 as Int:
print("zero as an Int")
case 0 as Double:
print("zero as a Double")
case let someInt as Int:
print("an Integer value of \\(someInt)")
case let someDouble as Double where someDouble > 0:
print("a positive value of \\(someDouble)")
case is Double:
print("some other double value that I don't want to print")
case let someString as String:
print("a string value of \\"\\(someString)\\"")
case let (x, y) as (Double, Double):
print("an (x, y) point at \\(x), \\(y)")
case let ev6 as EV6:
print(ev6.description)
case let stringConverter as (String) -> String:
print(stringConverter("soul"))
default:
print("something else : \\(type(of: item))")
}
}
checkAnyType(of: 0) // zero as an Int
checkAnyType(of: 0.0) // zero as a Double
checkAnyType(of: 42) // an Integer value of 42
checkAnyType(of: 3.1415) // a positive value of 3.1415
checkAnyType(of: -0.25) // some other double value that I don't want to print
checkAnyType(of: "Hello") // a string value of "Hello"
checkAnyType(of: (3.0, 5.0)) // an (x, y) point at 3.0, 5.0
checkAnyType(of: ev6) // Car has 5 door and fast speed
checkAnyType(of: car) // something else : Car
checkAnyType(of: {(name: String) -> String in "Hello, \\(name)"}) // Hello, soul
- 다양한 타입의 인스턴스를 전달인자로 호출했음
- 그as, let 값 바인딩 등을 사용하여 타입을 확인하고 동작을 확인
'programming > Swift' 카테고리의 다른 글
[Swift/iOS] 열거형(1) (1) | 2022.10.08 |
---|---|
앱 출시 후기 - Repret 과거 주가 확인, 만약 그때 샀으면... (1) | 2022.10.05 |
[Swift/iOS] 오류처리(1) - 오류처리, do-catch (0) | 2022.08.27 |
[Swift/iOS] 타입캐스팅(1) - 타입 변환, 타입캐스팅, 데이터 타입 확인, 메타 타입, 메타 타입 타입 (0) | 2022.08.26 |
[Swift/iOS] 기본 알람어플 만들기(2) - Tab bar Appearance(standard, scroll edge), 세계 시계, embed navigation, large title, bar button item (0) | 2022.07.30 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- escaping closrue
- autoclosure
- weak
- Core Data Stack
- authorizationCode
- 클로저표현
- identity Token
- 강한참조순환
- ios
- 디자인패턴
- Delegate 패턴
- 토큰저장
- Entity
- 강한 참조 순환
- 클로저 강한 참조
- 클로저
- 클로저 축약
- Persistent Container
- ASAuthorizationAppleIDCredential
- object
- 회원가입
- unowned
- inout 파라미터 메모리 충돌
- context
- 자동클로저
- 메모리 안정성
- core data
- 캡쳐리스트
- CoreData
- SWIFT
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
글 보관함