순진이의 하루/study정리
9. URLSession_2022.08.31
순진이
2022. 8. 31. 11:28
URLSession
- ViewController
import UIKit
class ViewController: UIViewController {
let temperatureLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
NetworkService.shared.fetch(urlString: URL.weather) { weatherInfo in
self.temperatureLabel.text = String(weatherInfo.main.temp)
}
}
}
//MARK: -UI
extension ViewController {
final private func configureUI() {
setAttributes()
setConstraints()
}
final private func setAttributes() {
temperatureLabel.text = "0"
}
final private func setConstraints() {
view.addSubview(temperatureLabel)
temperatureLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
temperatureLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
temperatureLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
- Model
import Foundation
struct WeatherInfo: Codable {
let main: Main
let weather: [Weather]
struct Main: Codable {
let temp: Double
}
struct Weather: Codable {
let main: String
}
}
- Service
import Foundation
// singleton으로 사용
class NetworkService {
static let shared = NetworkService()
func fetch(urlString: String, completion: @escaping (WeatherInfo)-> Void) {
URLSession.shared.dataTask(with: URL(string: urlString)!) { data, response, error in
// 1. error가 있다면
guard error == nil else { fatalError() }
// 2. response가 있으면서 응답 코드가 200 ~ 400 사이일 때 (응답이 성공했을 때)
guard let response = response as? HTTPURLResponse, (200..<400).contains(response.statusCode) else { fatalError() }
// 3. data가 있다면
guard let data = data else { return }
do {
let decodedData = try JSONDecoder().decode(WeatherInfo.self, from: data)
DispatchQueue.main.async {
// UI에 대한 작업이기 때문에 main thread에서 해줘야 함.
// main에서는 항상 async만 써야 함 (sync X)
print(Thread.isMainThread) // true
completion(decodedData)
}
} catch {
fatalError()
}
}.resume()
}
private init() {}
}
extension URL {
static let weather = "https://api.openweathermap.org/data/2.5/weather?q=seoul&appid"
}
1. 응답(response)는 HTTPURLResponse로 타입캐스팅 해줘야 함
guard let response = response as? HTTPURLResponse else { fatalError() }
2. 응답(response)이 성공일 경우에만 data 받아옴
guard let (200..<400).contains(response.statusCode) else { fatalError() }
3. 해당 thread가 메인 thread인지 확인하는 방법
print(Thread.isMainThread)
4. URLSession은 비동기적으로 일어나기 때문에 @escaping처리가 필요
func fetch(urlString: String, completion: @escaping (WeatherInfo)-> Void) { }