우선 Result 타입을 알아본 이유는 비동기 작업에서 에러 처리를 하다가 알게 된 키워드로 찾아보았습니다
Result
공식 문서
성공 또는 실패를 나타내는 값으로, 각 경우의 연관 값을 포함합니다
📌 Result 타입은 Swift 5 이전에 모든 오류를 전달 및 처리하는 데 유연성이 부족하여 하여 Swift 커뮤니티 내에서 일반적으로 사용하던 유형이었습니다. 더 복잡한 에러 처리 에러에 부합하지 않는 실패 값(즉, 비동기 작업)으로는 컴파일할 수가 없었기에 Result<Value, Error>로 단점을 해결하기 위해 추가 되었습니다
- SE-0235
실패할 수 있는 비동기 API 작성
실패할 수 있는 함수, 메서드 또는 기타 API를 작성할 때 선언에 throws 키워드를 사용하여 API 호출이 오류를 발생시킬 수 있음을 표시합니다. 그러나 비동기적으로 반환되는 API를 모델링하는 데는 throws 키워드를 사용할 수 없습니다. 대신, 비동기 호출의 성공 또는 실패 여부에 대한 정보를 캡처하려면 Result 열거형을 사용하고, 호출 결과에 대한 정보를 전달하려면 Result.success(*:) 및 Result.failure(*:) 케이스에 연결된 값을 사용하십시오.
let queue = DispatchQueue(label: "com.example.queue")
enum EntropyError: Error {
case entropyDepleted
}
struct AsyncRandomGenerator {
static let entropyLimit = 5
var count = 0
mutating func fetchRemoteRandomNumber(
completion: @escaping (Result<Int, EntropyError>) -> Void
) {
let result: Result<Int, EntropyError>
if count < AsyncRandomGenerator.entropyLimit {
// Produce numbers until reaching the entropy limit.
result = .success(Int.random(in: 1...100))
} else {
// Supply a failure reason when the caller hits the limit.
result = .failure(.entropyDepleted)
}
count += 1
// Delay to simulate an asynchronous source of entropy.
queue.asyncAfter(deadline: .now() + 2) {
completion(result)
}
}
}
var generator = AsyncRandomGenerator()
// Request one more number than the limit to trigger a failure.
(0..<AsyncRandomGenerator.entropyLimit + 1).forEach { _ in
generator.fetchRemoteRandomNumber { result in
switch result {
case .success(let number):
print(number)
case .failure(let error):
print("Source of randomness failed: \\(error)")
}
}
}
Throwing 표현식의 결과 보존
값을 던지거나 반환할 수 있는 함수 호출 또는 기타 표현식의 전체 결과를 보존해야 하는 경우가 있습니다. 예를 들어 결과를 직렬화하거나 결과 데이터를 처리하는 앱의 다른 부분에 값으로 전달해야 할 수 있습니다. 이러한 시나리오에서 유형을 사용하여 Result잠재적으로 실패한 작업의 결과를 캡처하십시오.
일반적으로 do-catch문으로 즉시 처리하지만 때로는 일괄 호출 분석과 같은 작업 중에 나중에 처리하기 위해 작업의 전체 결과를 저장해야 합니다.
enum EntropyError: Error {
case entropyDepleted
}
struct UnreliableRandomGenerator {
func random() throws -> Int {
if Bool.random() {
return Int.random(in: 1...100)
} else {
throw EntropyError.entropyDepleted
}
}
}
나중에 통계 분석을 위해 일련의 호출을 저장하는 더 넓은 맥락에서 이니셜라이저를 사용합니다.
struct RandomnessMonitor {
let randomnessSource: UnreliableRandomGenerator
var results: [Result<Int, Error>] = []
init(generator: UnreliableRandomGenerator) {
randomnessSource = generator
}
mutating func sample() {
let sample = Result { try randomnessSource.random() }
results.append(sample)
}
func summary() -> (Double, Double) {
let totals = results.reduce((sum: 0, count: 0)) { total, sample in
switch sample {
case .success(let number):
return (total.sum + number, total.count)
case .failure:
return (total.sum, total.count + 1)
}
}
return (
average: Double(totals.sum) / Double(results.count - totals.count),
failureRate: Double(totals.count) / Double(results.count)
)
}
}
Result의 사용
1. 타입 에러 (Typed Error)
enum LoadDataError: Error {
case invalidURL
case transportError
case serverError
case missingData
case decodingError
}
URLSession.default.dataTask(with: url) { data, response, error in
var result: Result<WantedData, LoadDataError>
guard error == nil else {
result = .failure(.transportError)
return
}
...
}
2. Throw 처리
get
성공 값을 throw 식으로 반환합니다
func get() throws -> Success
이 메서드를 사용하여 성공을 나타내는 경우 이 결과의 값을 검색하거나 실패를 나타내는 경우 값을 catch합니다.
let integerResult: Result<Int, Error> = .success(5)
do {
let value = try integerResult.get()
print("The value is \\(value).")
} catch {
print("Error retrieving the value: \\(error)")
}
// Prints "The value is 5."
3. 지연 처리 (Delayed Handling)
위에서 공식 문서의 예제를 확인하면 됩니다
4. Result 변형
Result는 map, flatmap, mapError 그리고 flatMapError 메서드가 존재합니다.
그 중에서도 mapError
mapError
주어진 변환을 사용하여 실패 값을 매핑하여 새 결과를 반환합니다.
func mapError<NewFailure>(_ transform: (Failure) -> NewFailure) -> Result<Success, NewFailure> where NewFailure : Error
Result 실패를 나타낼 때 인스턴스 값을 변환해야 하는 경우 이 방법을 사용합니다
'Language > Swift' 카테고리의 다른 글
[WWDC16] Understanding Swift Performance (2) (0) | 2023.08.02 |
---|---|
[WWDC16] Understanding Swift Performance (1) (0) | 2023.08.02 |
[Swift]UIAlertController (0) | 2023.01.11 |
[Swift] Unit Test (0) | 2023.01.10 |
[Swift] Class, Struct, Enum (0) | 2022.12.19 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!