🔥 에러 처리
프로그래밍을 하다 보면 예외 상황이 발생할 수 있어요. 이런 상황을 적절히 처리하는 것이 중요하죠. Swift에서는 Error
프로토콜을 채택한 타입을 사용하여 에러를 표현해요.
enum PrinterError: Error { case outOfPaper case noToner case onFire }
swift
위의 코드에서는 PrinterError
라는 열거형을 정의하고 있어요. 이 열거형은 프린터 관련 에러를 나타내는데, outOfPaper
, noToner
, onFire
와 같은 케이스를 가지고 있네요.
에러를 던지려면 throw
키워드를 사용하고, 에러를 던질 수 있는 함수라는 것을 표시하기 위해 throws
키워드를 사용해요. 함수 내에서 에러를 던지면, 함수는 즉시 반환되고 함수를 호출한 코드에서 에러를 처리하게 되죠.
func send(job: Int, toPrinter printerName: String) throws -> String { if printerName == "Never Has Toner" { throw PrinterError.noToner } return "Job sent" }
swift
위의 함수를 살펴볼까요? send(job:toPrinter:)
함수는 Int
타입의 job
과 String
타입의 printerName
을 매개변수로 받아요. 만약 printerName
이 "Never Has Toner"라면, PrinterError.noToner
에러를 던지게 되죠. 에러가 발생하지 않으면 "Job sent"라는 문자열을 반환해요.
에러를 처리하는 방법에는 여러 가지가 있어요. 그 중 하나는 do
-catch
구문을 사용하는 거예요. do
블록 내에서 에러를 던질 수 있는 코드 앞에 try
를 붙이고, catch
블록에서 에러를 처리하죠. 별도의 이름을 지정하지 않으면 에러는 자동으로 error
라는 이름을 갖게 돼요.
do { let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng") print(printerResponse) } catch { print(error) } // "Job sent" 출력
swift
위의 코드에서는 send(job:toPrinter:)
함수를 호출하고 있어요. 에러가 발생하지 않으면 printerResponse
에 "Job sent"가 할당되고, 이를 출력하죠. 에러가 발생하면 catch
블록에서 에러를 출력해요.
특정 에러를 처리하기 위해 여러 개의 catch
블록을 제공할 수도 있어요. switch
문의 case
처럼 catch
뒤에 패턴을 작성하면 되죠.
do { let printerResponse = try send(job: 1440, toPrinter: "Gutenberg") print(printerResponse) } catch PrinterError.onFire { print("I'll just put this over here, with the rest of the fire.") } catch let printerError as PrinterError { print("Printer error: \(printerError).") } catch { print(error) } // "Job sent" 출력
swift
위의 코드에서는 PrinterError.onFire
에러를 별도로 처리하고 있어요. 그 외의 PrinterError
에러는 printerError
라는 이름으로 바인딩하여 처리하고 있죠. 마지막 catch
블록은 그 외의 모든 에러를 처리해요.
에러를 처리하는 또 다른 방법은 try?
를 사용하여 결과를 옵셔널로 변환하는 거예요. 함수가 에러를 던지면 특정 에러는 무시되고 결과는 nil
이 되죠. 에러가 발생하지 않으면 함수가 반환한 값을 담은 옵셔널이 결과가 돼요.
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler") let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
swift
위의 코드에서 printerSuccess
는 옵셔널 문자열이 되고, printerFailure
는 nil
이 되겠죠?
defer
키워드를 사용하면 함수의 다른 모든 코드가 실행된 후, 함수가 반환되기 직전에 실행되는 코드 블록을 작성할 수 있어요. 함수가 에러를 던지는지 여부와 관계없이 코드가 실행되죠. defer
를 사용하면 설정 코드와 정리 코드를 나란히 작성할 수 있어요. 실행 시점은 달라도 말이죠.
var fridgeIsOpen = false let fridgeContent = ["milk", "eggs", "leftovers"] func fridgeContains(_ food: String) -> Bool { fridgeIsOpen = true defer { fridgeIsOpen = false } let result = fridgeContent.contains(food) return result } if fridgeContains("banana") { print("Found a banana") } print(fridgeIsOpen) // "false" 출력
swift
위의 코드에서 fridgeContains(_:)
함수는 fridgeIsOpen
을 true
로 설정한 후, defer
블록에서 fridgeIsOpen
을 다시 false
로 설정하고 있어요. 함수가 반환되기 직전에 defer
블록이 실행되므로, fridgeIsOpen
은 항상 false
로 설정되겠죠?
에러 처리는 프로그래밍에서 매우 중요해요. Swift는 에러 처리를 위한 다양한 방법을 제공하고 있죠. 상황에 맞는 적절한 에러 처리 방식을 선택하여 사용하면 됩니다. 그러면 더 안정적이고 예외 상황에 잘 대응할 수 있는 코드를 작성할 수 있을 거예요!