Swift에서 타입캐스팅(type casting)은 인스턴스를 다른 타입으로 변환하거나 확인하는 방법이다. 이는 클래스 계층 구조에서 주로 사용되며, 특정 타입의 인스턴스인지 확인하거나, 더 상위 또는 하위 타입으로 변환할 때 사용된다.
타입캐스팅에 사용되는 키워드:
1. is
2. as
(as?
, as!
포함)
is
특정 인스턴스가 해당 타입에 속하는지 확인한다. is
는 Boolean 값을 반환한다.
let someValue: Any = "Hello, Swift!"
if someValue is String {
print("someValue는 String 타입입니다.")
}
as
타입 변환에 사용되며, 세 가지 형태가 있다:
as
protocol Greetable {
func greet()
}
class Person: Greetable {
func greet() {
print("Hello!")
}
}
let person = Person()
let greeter: Greetable = person as Greetable // 명시적 프로토콜 캐스팅
as?
(Optional Casting)nil
을 반환함let unknownValue: Any = "I am a string"
if let stringValue = unknownValue as? String {
print("Casting 성공: \(stringValue)")
} else {
print("Casting 실패")
}
as!
(Forced Casting)let anotherValue: Any = 42
let integerValue = anotherValue as! Int // 강제 변환
print("변환된 값: \(integerValue)")
클래스 계층에서 상위 타입과 하위 타입 간 변환에 자주 사용된다.
class Animal {
func makeSound() {
print("Animal sound")
}
}
class Dog: Animal {
func bark() {
print("Woof!")
}
}
let myAnimal: Animal = Dog() // 업캐스팅
myAnimal.makeSound()
// 다운캐스팅
if let myDog = myAnimal as? Dog {
myDog.bark()
}
Swift의 do-catch
구문은 에러 처리(Error Handling)를 위한 구문으로, 오류가 발생할 가능성이 있는 코드를 안전하게 실행하고 오류를 처리하는 데 사용된다.
do-catch
구문의 기본 구조는 다음과 같다:
do {
// 에러가 발생할 가능성이 있는 코드
} catch {
// 에러를 처리하는 코드
}
do {
let result = try someThrowingFunction() // 에러를 던질 수 있는 함수 호출
print("Result: \(result)")
} catch {
print("An error occurred: \(error)")
}
do
: 오류가 발생할 가능성이 있는 코드를 포함하는 블록try
: 에러를 던질 가능성이 있는 함수 호출 전에 사용catch
: 발생한 에러를 처리하는 블록. 다양한 조건에 따라 여러 catch
블록을 정의할 수 있음catch
블록 처리여러 종류의 에러를 구분하여 처리할 수 있다.
enum MyError: Error {
case invalidInput
case networkError
}
func throwingFunction(_ value: Int) throws -> String {
if value < 0 {
throw MyError.invalidInput
} else if value == 0 {
throw MyError.networkError
}
return "Success"
}
do {
let result = try throwingFunction(0)
print(result)
} catch MyError.invalidInput {
print("Invalid input error")
} catch MyError.networkError {
print("Network error occurred")
} catch {
print("Unknown error: \(error)")
}
에러를 무시하고 처리하지 않을 때는 try?
를 사용할 수 있다.
let result = try? throwingFunction(1) // 에러 발생 시 nil 반환
print(result ?? "No result")
try!
를 사용하면 에러가 발생하지 않는다는 것을 확신할 때 사용한다. 하지만 실제로 에러가 발생하면 런타임 에러가 발생한다.
let result = try! throwingFunction(1) // 에러 발생 시 앱 크래시
print(result)
func divide(_ a: Int, by b: Int) throws -> Int {
if b == 0 {
throw NSError(domain: "DivideByZero", code: 1, userInfo: nil)
}
return a / b
}
do {
let result = try divide(10, by: 0)
print("Result: \(result)")
} catch {
print("Error: \(error)")
}
Swift에서 throws
와 throw
는 에러 처리에 사용되며, 서로 다른 역할을 한다.
throws
정의: 함수나 메서드가 에러를 발생시킬 수 있음을 선언하는 키워드
위치: 함수의 시그니처에 사용
의미: 이 함수를 호출할 때 에러를 처리해야 함
예시:
func canThrowError() throws {
// 에러를 던질 가능성이 있는 코드
}
호출 시에는 try
키워드가 필요:
do {
try canThrowError()
} catch {
print("Error caught: \(error)")
}
throw
정의: 실제로 에러를 발생시킬 때 사용하는 키워드
위치: do
블록이나 함수 내부에서 사용
의미: 선언된 에러를 발생시킴
예시:
enum MyError: Error {
case somethingWentWrong
}
func throwErrorExample() throws {
throw MyError.somethingWentWrong
}
위의 함수는 호출 시 다음과 같이 에러를 던진다:
do {
try throwErrorExample()
} catch {
print("Caught an error: \(error)")
}
키워드 | 역할 | 사용 위치 |
---|---|---|
throws | 함수가 에러를 던질 수 있음 선언 | 함수 시그니처 |
throw | 에러를 실제로 던짐 | 함수/메서드 내부 |
enum DivisionError: Error {
case divideByZero
}
func divide(_ a: Int, by b: Int) throws -> Int {
if b == 0 {
throw DivisionError.divideByZero // 실제 에러 발생
}
return a / b
}
do {
let result = try divide(10, by: 0) // throws로 선언된 함수 호출
print(result)
} catch {
print("Error: \(error)") // throw로 발생한 에러를 처리
}
Swift의 Error
타입은 에러를 표현하고 처리하는 표준 프로토콜이다. 사용자 정의 에러 타입을 만들거나 Swift에서 제공하는 기본 에러를 사용할 때 기반이 되는 구조이다.
Error
프로토콜Error
는 빈 프로토콜로, 특정 규칙을 강제하지 않는다. 대신, Swift에서 에러를 던지고 처리하기 위해 이 타입을 따르는 객체로 정의해야 한다.
protocol Error {}
이 프로토콜을 채택하면 에러로 사용할 수 있는 타입을 만들 수 있다.
주로 열거형(enum)을 사용하여 에러를 정의한다. 열거형은 에러의 다양한 상태를 명확하게 표현할 수 있기 때문이다.
enum MyError: Error {
case invalidInput
case networkFailure(code: Int)
case unknown
}
Error
를 준수하는 타입으로 에러 정의throw
를 사용하여 에러 발생do-catch
구문을 사용하여 에러 처리Error
타입의 활용Error
타입에 연관 값을 추가하여, 발생한 에러에 대한 추가 정보를 전달할 수 있다.
enum NetworkError: Error {
case timeout
case serverError(message: String)
case unknown
}
func fetchData() throws {
throw NetworkError.serverError(message: "Internal Server Error")
}
do {
try fetchData()
} catch NetworkError.serverError(let message) {
print("Server Error: \(message)")
} catch {
print("An error occurred: \(error)")
}
Error
타입을 사람이 읽기 쉬운 메시지로 변환하려면 CustomStringConvertible
을 채택한다.
enum FileError: Error, CustomStringConvertible {
case fileNotFound(String)
case unreadable(String)
var description: String {
switch self {
case .fileNotFound(let fileName):
return "File '\(fileName)' not found."
case .unreadable(let fileName):
return "File '\(fileName)' cannot be read."
}
}
}
do {
throw FileError.fileNotFound("data.txt")
} catch {
print(error) // File 'data.txt' not found.
}
Swift에서는 몇 가지 기본 제공 에러 타입이 있다.
NSError
: Objective-C와 상호작용할 때 사용. 주로 Foundation 프레임워크에서 발생DecodingError
, EncodingError
: JSON 인코딩/디코딩에서 발생URLError
: URL 요청과 관련된 에러