struct ClosureWeatherService {
func fetchWeather(for city: String, completion: (ClosureWeather) -> Void) {
let weather = ClosureWeather(city: city, temperature: 21, imageName: "sunset.fill")
completion(weather)
}
}
Call it from a ViewController like this.
@objc func weatherPressed() {
var weatherService = ClosureWeatherService()
// Simple closure
weatherService.fetchWeather(for: "San Francisco") { (weather) in
updateView(with: weather)
}
}
Here the weather is passed back to the ViewController via the closure completion block.
Closures can return variables too.
struct ClosureWeatherService {
var cacheable = false
var weather = ClosureWeather(city: "Unknown", temperature: 0, imageName: "moon")
mutating func fetchWeather(for city: String, completion: (ClosureWeather) -> Bool) {
if cacheable {
cacheable = completion(weather)
return
}
weather = ClosureWeather(city: city, temperature: -30, imageName: "snow")
cacheable = completion(weather)
}
}
Which we call like this. Note: The return.
weatherService.fetchWeather(for: "New York") { (weather) -> Bool in
updateView(with: weather)
return weather.temperature < -20
}
The pattern of returning success/fail has become so common Swift has codified that into an enum called Result
.
func fetchWeatherWithResult(for city: String, completion: (Result<ClosureWeather, Error>) -> Void) {
weather = ClosureWeather(city: city, temperature: 15, imageName: "wind")
completion(Result.success(weather))
// if error
// enum WeatherError: Error { case failure }
// completion(Swift.Result.failure(WeatherError.failure))
}
Which we call from our viewController like this
@objc func weatherPressed() {
weatherService.fetchWeatherWithResult(for: "Seattle") { (result) in
switch result {
case .success(let weather):
updateView(with: weather)
case .failure(_):
print("Error 💥! ")
}
}
}
struct ClosureWeather {
typealias Celcius = Int
let city: String
let temperature: Celcius
let imageName: String
}