웬만하면 코딩을 하면서 nil보다는 throw를 하려고 한다. 예를 들어
let dict = [String: String]()
func getValue(key: String) -> String? {
guard key.count >= 10 else { return nil }
return dict[key]
}
key는 반드시 10글자가 넘어야 된다고 가정하자.
위 코드를 getValue
함수가 nil
반환 되는 경우는 크게 2가지다.
key가 10글자가 안되는 경우
dict에 key가 없는 경우
만약 저 함수를 사용하는 입장에서는
그래서 왜 nil이 반환되는 거지?
라는 의문을 품게된다. 그래서 그러한 오해의 소지가 없게
let dict = [String: String]()
func getValue(key: String) throws -> String {
guard key.count >= 10 else { throw CustomError.keyIsShort }
guard let result = dict[key] else { throw CustomError.notExist }
return result
}
enum CustomError: Error {
case keyIsShort
case notExist
}
위 처럼 쓰면 사용자 입장에서는 왜 저 함수가 정상적으로 작동하지 않는지 알 수 있다.
여기서 다가오는 2번째 문제다. 저렇게 코딩하는 습관을 들여놓으니 do-catch가 귀찮지만
확실히 디버깅할 때 어디서 문제가 생겼는지 파악이 쉬워졌다.
하지만 2번째 문제가 여기서 생겼다.
내가 던지는 에러들에 대해서는 처리가 쉬웠지만, Framework에서 던지는 Error들에 대해서는 구분이 쉽지가 않다는 것이다.
Framework에서 던지는 Error에 대해서는 error.localizedDescription
로 파악이 쉬웠다.
하지만 내가 던지는 Error에는 localizedDescription 이 없었기에
왜 에러가 일어났는지 localizedDescription으로 찍으면 print 바로 확인할 수 있다면
에러 처리가 더 수월해질 것 같아서 만들어보고자 함
LocalizedError
/// Describes an error that provides localized messages describing why
/// an error occurred and provides more information about the error.
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
public protocol LocalizedError : Error {
/// A localized message describing what error occurred.
var errorDescription: String? { get }
/// A localized message describing the reason for the failure.
var failureReason: String? { get }
/// A localized message describing how one might recover from the failure.
var recoverySuggestion: String? { get }
/// A localized message providing "help" text if the user requests help.
var helpAnchor: String? { get }
}
주석을 보면. 에러 왜 발생했는지 에러메세지도 같이 던지고 싶으면 쓰라고 적혀있음
설명이 잘 적혀 있으므로 주석을 직접 참조하면 좋을 것 같다.
Default는 print(error.localizedDescription)
을 하면 다음과 같이 나온다.
The operation couldn’t be completed. (SwiftTest.CustomError error 0.)
The operation couldn’t be completed.
: default - errorDescription
(SwiftTest.CustomError error 0.)
failureReason
+)SwiftTest 프로젝트 - CustomError enum - 0번째 case 라는 의미
그럼 커스텀 해보자.
enum CustomError: LocalizedError {
case keyIsShort
case notExist
var errorDescription: String? {
switch self {
case .keyIsShort: "Key is too short"
case .notExist: "Value is not exist"
}
}
var failureReason: String? {
switch self {
case .keyIsShort: "key.count < 10"
case .notExist: "dict[key] == nil"
}
}
var recoverySuggestion: String? {
switch self {
case .keyIsShort: "Key를 10글자 이상으로 하세요."
case .notExist: "Value를 추가해주세요."
}
}
var helpAnchor: String? {
switch self {
case .keyIsShort: "글자 더 많이 추가하세요"
case .notExist: "데이터 추가 함수를 사용해보세요."
}
}
}
errorDescription
을 override하면 failureReason은 별도로 출력해야한다.
저는 그냥 errorDescription에 추가함
do {
let a = try getValue(key: "dgdgsdgsdgds")
} catch let error as CustomError {
print(error.localizedDescription)
print(error.failureReason)
}
// Value is not exist
// dict[key] == nil
do {
let a = try getValue(key: "dgdgsdgsdgds")
} catch {
print(error.localizedDescription)
}
// Value is not exist
Casting을 하면 localizedDescription 외 변수에 직접 접근이 가능하지만
그냥 쓰면 Error 타입이기에 직접 접근이 안된다.
참조한 사이트