LoginSignup
0
0

More than 1 year has passed since last update.

SwiftでOpenWeatherAPIを使ってみる

Last updated at Posted at 2021-09-01

はじめに

SwiftでOpenWeatherAPIを使って天気予報アプリを作ってみたいと思います。
初心者にもわかりやすく、AutoLayoutの設定、デザインパターン、コードの可読性もしっかり守っているので、APIの入門記事としてはぴったりかなと。
まず完成形はこちら!

ezgif.com-gif-maker (2).gif

では始めていきます。ぜひ最後までご覧ください。

UIの設計

まずこのアプリでは以下の画像を使ったのでここからダウンロードしてください。
このように配置していきます。
スクリーンショット 2021-08-31 11.39.52.png

制約をつけていきます。
seiyaku.png

WeatherViewControllerを作り、IBOutlet,IBAction接続します。
スクリーンショット 2021-08-31 12.54.39.png

WeatherViewController.swift
class WeatherViewController: UIViewController{

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temparatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func searchPressed(_ sender: UIButton) {
    }
}

全体設計

UIができた後に、今回のアプリの設計を行なっていく。
スクリーンショット 2021-09-01 13.44.41.png

スクリーンショット 2021-09-01 13.59.13.png

APIの取得

まず、APIの取得からやっていきたいと思います。
OpenWeatherAPIを使います。
こちらでサインインして、APIKeyを取得します。
今回はCurrentWeatherDataを使います。
スクリーンショット 2021-09-01 14.20.15.png

こちらでこのようにAPIを叩くと、JSONデータを変換してくれます。
スクリーンショット 2021-09-01 14.19.28.png
これらのデータをうまく使い今回はアプリを作成していきます。

WeatherManager

今回のAPIにおいてのロジックを管理するWeatherManagerを書いていきます。

WeatherViewController.swift
import Foundation

//UI更新のためのプロトコル
protocol WeatherManagerDelegate {
    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel)
    func didFailWithError(error: Error)
}

struct WeatherManager {
    //[APIKey]には自分のAPIKeyをかく
    let weatherURL = "https://api.openweathermap.org/data/2.5/weather?appid=[APIKey]&units=metric"

    var delegate: WeatherManagerDelegate?

    func fetchWeather(cityName: String) {
        let urlString = "\(weatherURL)&q=\(cityName)"
        performRequest(with: urlString)
    }

    func performRequest(with urlString: String) {
        func performRequest(with urlString:String){
        //①URL型に変換
        if let url = URL(string: urlString){
            //②URLSessionを作る
            let session = URLSession(configuration: .default)

            //③Session taskを与える
            let task = session.dataTask(with: url) { data, response, error in
                if error != nil {
                    self.delegate?.didFailWithError(error: error!)
                    return
                }

                if let safeData = data {
                    if let weather = self.parseJSON(safeData){
                        self.delegate?.didUpdateWeather(self, weather: weather)
                    }
                }
            }
            //④タスクが始まる
            task.resume()
        }
    }

    func parseJSON(_ weatherData: Data) -> WeatherModel? {
        let decoder = JSONDecoder()
        do {
            //JSONを変換
            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
            let id = decodedData.weather[0].id
            let temp = decodedData.main.temp
            let name = decodedData.name

                        //データをアプリで使いやすいようにまとめる
            let weather = WeatherModel(conditionId: id, cityName: name, temperature: temp)
            return weather

        } catch {
            delegate?.didFailWithError(error: error)
            return nil
        }
    }

}


WeatherModel

データをアプリが使いやすいような形に変換するためのWeatherModelを作成していきます。

WeatherModel.swift
import Foundation

struct WeatherModel {
    let conditionId:Int
    let cityName:String
    let temperature:Double

    var temperatureString:String {
        return String(format: "%.1f",temperature)
    }

    var conditinName:String{
        switch conditionId {
        case 200...232:
            return "cloud.bolt"
        case 300...321:
            return "cloud.drizzle"
        case 500...531:
            return "cloud-rain"
        case 600...622:
            return "cloud-snow"
        case 701...781:
            return "cloud-fog"
        case 800:
            return "sun.max"
        case 801...804:
            return "cloud.bolt"
        default:
            return "cloud"
        }
    }
}

WeatherData

レスポンスしたデータをデコードするためWeatherDataを作ります。

WeatherData.swift
import Foundation

//Codable = Decodable & Encodable
struct WeatherData : Codable{
    let name:String
    let main:Main
    let weather:[Weather]
}

struct Main:Codable {
    let temp:Double
}

struct Weather:Codable {
    let description:String
    let id:Int
}

WeatherViewController

最後に取得したデータをViewに反映させる、またTableViewの操作のためにWeatherViewControllerを作っていきます。

WeatherViewController
import UIKit

class WeatherViewController: UIViewController {

    @IBOutlet weak var conditionImageView: UIImageView!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!

    var weatherManager = WeatherManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        weatherManager.delegate = self
        searchTextField.delegate = self
    }

}

//MARK: - UITextFieldDelegate
extension WeatherViewController: UITextFieldDelegate {

    @IBAction func searchPressed(_ sender: UIButton) {
        searchTextField.endEditing(true)
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        searchTextField.endEditing(true)
        return true
    }

    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        if textField.text != "" {
            return true
        } else {
            textField.placeholder = "何か入力してください"
            return false
        }
    }

    func textFieldDidEndEditing(_ textField: UITextField) {

        if let city = searchTextField.text {
            weatherManager.fetchWeather(cityName: city)
        }

        searchTextField.text = ""

    }
}

//MARK: - WeatherManagerDelegate

extension WeatherViewController: WeatherManagerDelegate {

    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
        DispatchQueue.main.async {
            //ここでUIの更新
            self.temperatureLabel.text = weather.temperatureString
            self.conditionImageView.image = UIImage(systemName: weather.conditionName)
            self.cityLabel.text = weather.cityName
        }
    }

    func didFailWithError(error: Error) {
        print(error)
    }
}

UITextFieldの処理はUITextFieldのドキュメントを確認しながら学んでください。

終わりに

以上でこのようなアプリが作成できました。
ezgif.com-gif-maker (2).gif

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0