Result νμ μ μ±κ³΅κ³Ό μ€ν¨ λ κ°μ§ κ°λ₯ν κ²°κ³Όλ₯Ό λνλ΄κΈ° μν΄ μ¬μ©λλ€.
Result νμ μ μ΄κ±°νμΌλ‘, μ±κ³΅ μμλ κ°μ λ°ννκ³ μ€ν¨ μμλ μ€λ₯λ₯Ό λ°ννλ€.
enum Result<Success, Failure> where Failure : Error {
case success(Success)
case failure(Failure)
}
Success(μ°κ΄κ°): μμ μ΄ μ±κ³΅νμ λ λ°νλλ κ°μ νμ .
Failure(μ°κ΄κ°): μμ μ΄ μ€ν¨νμ λ λ°νλλ μ€λ₯μ νμ . Failureλ λ°λμ Error νλ‘ν μ½μ μ€μν΄μΌ νλ€.
κ·Έλ λ€λ©΄ Result νμ μ μ μ°λ건λ°?
- λͺ νν μ€λ₯ μ²λ¦¬: Result νμ μ μ¬μ©νλ©΄ μ±κ³΅κ³Ό μ€ν¨λ₯Ό λͺ ννκ² κ΅¬λΆν μ μλ€.
- κ°λ μ± ν₯μ: μ½λμ κ°λ μ±μ΄ ν₯μλκ³ , μ€λ₯ μ²λ¦¬ λ‘μ§μ΄ κ°κ²°ν΄μ§λ€.
- νμ μμ μ±: Result νμ μ μ λ€λ¦μ μ¬μ©νλ―λ‘, μ±κ³΅κ³Ό μ€ν¨μ λν νμ μ λͺ ννκ² μ§μ ν μ μλ€.
Result νμ μ μ¬μ© μμ
κΈ°μ‘΄μ completion ν΄λ‘μ λ₯Ό Result νμ μΌλ‘ λ³ννμ¬ μ¬μ©ν΄λ³΄κΈ°
1. κΈ°μ‘΄ completion ν΄λ‘μ
κΈ°μ‘΄μ completion ν΄λ‘μ λ ([Movie]?) -> Void ννλ‘ μ μλμλ€.
func fetchMovies(completion: @escaping ([Movie]?) -> Void) {
// λ€νΈμν¬ μμ² λ° μλ΅ μ²λ¦¬ λ‘μ§
}
2. Result νμ μ μ¬μ©νλ completion ν΄λ‘μ
// NetworkError μ μ
enum NetworkError: Error {
case invalidURL
case noData
}
func fetchMovies(completion: @escaping (Result<[Movie], Error>) -> Void) {
guard let url = URL(string: "https://api.example.com/movies") else {
completion(.failure(NetworkError.invalidURL)) // μ ν¨νμ§ μμ URL μ€λ₯ μ λ¬
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(error)) // λ€νΈμν¬ μ€λ₯ μ λ¬
return
}
guard let data = data else {
completion(.failure(NetworkError.noData)) // λ°μ΄ν°κ° μλ κ²½μ° μ€λ₯ μ λ¬
return
}
// JSON λμ½λ©
do {
let decoder = JSONDecoder()
let result = try decoder.decode(MovieResponse.self, from: data)
completion(.success(result.results)) // μ±κ³΅μ μΌλ‘ λμ½λ©λ μν λͺ©λ‘ μ λ¬
} catch let jsonError {
completion(.failure(jsonError)) // JSON λμ½λ© μ€λ₯ μ λ¬
}
}
task.resume()
}
β completion(.failure(NetworkError.invalidURL))μ κ°μ΄ .failureλ‘ μ κ·Όν μ μλ μ΄μ ?
Result νμ μ΄ μ΄κ±°ν(enum)μΌλ‘ μ μλμ΄ μκΈ° λλ¬Έμ΄λ€.
μ΄κ±°ν μ΄λ¦μ νμ μΈ Result μλ΅ κ°λ₯.
β completion(.success(result.results))μμ resultsλ result κ°μ²΄μ μμ±!
struct MovieResponse: Decodable {
let results: [Movie]
}
MovieResponseλ API μλ΅ λ°μ΄ν°λ₯Ό λνλ΄λ ꡬ쑰체λ€.
MovieResponse ꡬ쑰체λ resultsλΌλ μμ±μ κ°μ§κ³ μκ³ , μ΄λ μν λͺ©λ‘μ λνλΈλ€.
fetchMovies ν¨μ λ΄μμ JSON λ°μ΄ν°λ₯Ό λμ½λ©ν λ, MovieResponse κ°μ²΄κ° μμ±λλ€.
3. λ·° 컨νΈλ‘€λ¬μμ fetchMovies μ¬μ©νκΈ°
fetchMovies ν¨μλ₯Ό λ·° 컨νΈλ‘€λ¬μμ νΈμΆνκ³ , λ€νΈμν¬ μμ²μ ν΅ν΄ λ°μ΄ν°λ₯Ό λ°μμ
ν μ΄λΈ λ·°λ₯Ό μ λ°μ΄νΈν λ μλμ κ°μ΄ μ¬μ©ν μ μλ€.
import UIKit
class MoviesViewController: UIViewController, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
var movies: [Movie] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
// fetchMovies ν¨μ νΈμΆ
fetchMovies { result in
DispatchQueue.main.async {
switch result {
case .success(let movies):
self.movies = movies
self.tableView.reloadData() // ν
μ΄λΈ λ·° μ
λ°μ΄νΈ
case .failure(let error):
// μ€λ₯ μ²λ¦¬
switch error {
case NetworkError.invalidURL:
print("Invalid URL error occurred.")
case NetworkError.noData:
print("No data returned from the server.")
default:
print("An error occurred: \(error.localizedDescription)")
}
}
}
}
}
// UITableViewDataSource λ©μλ ꡬν
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath)
let movie = movies[indexPath.row]
cell.textLabel?.text = movie.title
return cell
}
// μ€λ₯ μλ¦Ό νμ λ©μλ
private func showAlert(for error: Error) {
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}
completion ν΄λ‘μ μ μΈμλ‘ resultκ° μ λλ€. resultλ Result<[Movie], Error> νμ μ΄λ€.
switch resultλ₯Ό ν΅ν΄ resultμ μ±κ³΅(.success)κ³Ό μ€ν¨(.failure)λ₯Ό ꡬλΆνλ€.