import Foundation
struct Constants {
struct URLs {
static func weather(city: String) -> String { "http://api.openweathermap.org/data/2.5/weather?q=\(city)&appid=yourapikey&units=imperial" }
// celsius = metric
}
}
import Foundation
struct WeatherResponse: Decodable {
let main: Weather
}
struct Weather: Decodable {
let temp: Double?
let humidity: Double?
static var placeholder: Weather {
return Weather(temp: nil, humidity: nil)
}
}
class Webservice {
func fetchWeather(city: String) -> AnyPublisher<Weather, Error> {
guard let url = URL(string: Constants.URLs.weather(city: city)) else {
fatalError("Invalid URL")
}
return URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data }
.decode(type: WeatherResponse.self, decoder: JSONDecoder())
.map { $0.main }
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
}
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet weak var cityTextField: UITextField!
@IBOutlet weak var temperatureLabel: UILabel!
private var webservice: Webservice = Webservice()
private var cancellable: AnyCancellable?
override func viewDidLoad() {
super.viewDidLoad()
setupPublishers()
// self.cancellable = self.webservice.fetchWeather(city: "Houston")
// .catch{_ in Just(Weather.placeholder)}
// .map { weather in
// if let temp = weather.temp {
// return "\(temp)"
// } else {
// return "Error getting weather!"
// }
// }
// .assign(to: \.text, on: self.temperatureLabel)
}
private func setupPublishers() {
let publisher = NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: self.cityTextField)
self.cancellable = publisher.compactMap {
($0.object as! UITextField).text?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
}.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.flatMap { city in
return self.webservice.fetchWeather(city: city)
.catch { _ in Just(Weather.placeholder) }
.map { $0 }
}.sink {
if let temp = $0.temp {
self.temperatureLabel.text = "\(temp) ℉"
} else {
self.temperatureLabel.text = ""
}
}
}
}