728x90
https://openweathermap.org/api/one-call-3
- Create a Model Struct
- Decode JSON
날씨앱을 만들기 위해서 OpenWeatherMap에서 api를 받아와서 데이터를 얻을 수 있다. 이를 JSON 파일로 바꾸고 이걸 참고해서 Model Struct를 만들면 편하다!
날씨앱에서 어떤 데이터를 사용할 것인지 확인하고 Model Struct를 만들어주면 된다.
예시)
import Foundation
import UIKit
struct Weather: Codable{
struct Daily: Codable{
let dt : Date
struct Temp: Codable{
let min: Double
let max: Double
}
let temp: Temp
let humidity: Int
struct Weather: Codable{
let id: Int
let description: String
let icon: String
var weatherIconURL: URL{
let urlString = "http://openweathermap.org/img/wn/\(icon)@2x.png"
return URL(string: urlString)!
}
}
let weather: [Weather]
let clouds: Int
let pop: Double
}
let daily: [Daily]
}
- Creating an APIService Singleton Class
🚨What is the Singleton?
보통 자원을 집약적으로 만드는 것과 객체에 대해 최초 한번 초기화할 때 사용된다 → DB 연결, Login 등
import Foundation
import Combine
public class APIService{
public static let shared = APIService()
var cancellable = Set<AnyCancellable>()
public enum APIError: Error{
case error(_ errorString: String)
}
public func getJSON<T: Decodable>(urlString: String,
dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys,
completion: @escaping(Result<T, APIError>) -> Void){
guard let url = URL(string: urlString) else {completion(.failure(.error(NSLocalizedString("Error: Invalid URL", comment: ""))))
return
}
let request = URLRequest(url: url)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
URLSession.shared.dataTaskPublisher(for: request)
.map{ $0.data }
.decode(type: T.self, decoder: decoder)
.receive(on: RunLoop.main)
.sink{(taskCompletion) in
switch taskCompletion {
case .finished:
return
case .failure(let decodingError):
completion(.failure(APIError.error("Error: \(decodingError.localizedDescription)")))
}
} receiveValue: { (decodedData) in
completion(.success(decodedData))
}
.store(in: &cancellable)
}
}
- API에서 데이터 가져와서 출력하기
import SwiftUI
import CoreLocation
struct ContentView: View {
@State private var location: String = ""
var body: some View {
VStack{
HStack{
TextField("Enter location", text: $location)
Button{
getWeatherForecast(for: location)
}label: {
Image(systemName: "circle.fill")
}
}
}
}
func getWeatherForecast(for location: String){
let apiService = APIService.shared
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "E, MMM, d"
CLGeocoder().geocodeAddressString(location){ (placemarks, error) in
if let error = error {
print(error.localizedDescription)
}
if let lat = placemarks?.first?.location?.coordinate.latitude,
let lon = placemarks?.first?.location?.coordinate.longitude {
apiService.getJSON(urlString: "/user's api/",
dateDecodingStrategy: .secondsSince1970) { (result: Result<Weather, APIService.APIError>) in
switch result {
case .success(let weather):
for day in weather.daily{
print(dateFormatter.string(from: day.dt))
print(" Max: ", day.temp.max)
print(" Min: ", day.temp.min)
print(" Humidity: ", day.humidity)
print(" Description: ", day.weather[0].description)
print(" Clouds: ", day.clouds)
print(" pop: ", day.pop)
print(" IconURL: ", day.weather[0].weatherIconURL)
}
case .failure(let apiError):
switch apiError{
case .error(let errorString):
print(errorString)
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
728x90
'iOS' 카테고리의 다른 글
[SwiftUI] .listRowBackground(_:) : List의 전체/특정 row 커스텀하기 (0) | 2022.09.29 |
---|---|
[SwiftUI] View Modifier - customize your object! (1) | 2022.09.29 |
[iOS] Swift Package Manager 사용하기 (0) | 2022.08.11 |
[Button] 버튼 둥글게 Custom하기! (0) | 2022.07.01 |
[TextField] 키보드 내리기, 버튼 활성화, 자동으로 커서 올리기 (0) | 2022.07.01 |