##はじめに
初心者が学習を兼ねて、作ってみました。
暖かい目でお願いします。
変なところがあったら教えてください!
##環境
Swift 5.1.2
Xcode 11.2
使用したお天気api
http://weather.livedoor.com/weather_hacks/webservice
##Podをインストールする
pod "Alamofire"
pod "SwiftyJSON"
この2つのライブラリをインストールする事で、
簡単にHTTP通信と、JSONを扱うことができます。
##Main.storyboardを作る
こんな感じでパーツを配置します。
今回はpickerViewを使用して、地域を選択できるようにします。
あとはラベルとボタンを、いい感じに配置します。
ボタンを押すと、選択した地域の天気予報を取得し、次の画面でラベルに反映するようにします。
とてもシンプルです。
また、今回はNavigation Controllerを使用しています。
タブのEditor -> Embed In -> Navigation Controller
で使用できます。
##実装する
まずは、pickerViewに入れるデータをmodelに書いておきます。
import Foundation
class CityModel {
//地域の名前とURL追加するプロパティを持ちます。
let code: String
let name: String
init(cityCode:String, cityName:String) {
code = cityCode
name = cityName
}
}
import Foundation
class CityList {
var list = [CityModel]()
//Webサイトを見て適当に地域を追加します。
init() {
list.append(CityModel(cityCode: "016010", cityName: "札幌"))
list.append(CityModel(cityCode: "015010", cityName: "室蘭"))
list.append(CityModel(cityCode: "040010", cityName: "仙台"))
list.append(CityModel(cityCode: "110010", cityName: "さいたま"))
list.append(CityModel(cityCode: "130010", cityName: "東京"))
list.append(CityModel(cityCode: "140010", cityName: "横浜"))
}
}
次に、最初の画面の処理を書いていきます。
この画面では、選択したデータを次の画面に渡すだけです。
import UIKit
//pickerを使うので、DelegateとDataSourceを追加します。
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var pickerView: UIPickerView!
@IBOutlet weak var resultButton: UIButton!
//次のVCに渡す変数に初期値を入れておきます。
var cityData:[String] = ["016010", "札幌"]
//modelのデータを持ってきます。
let cityList = CityList()
override func viewDidLoad() {
super.viewDidLoad()
//pickerを使うので、デリゲートを設定します。
pickerView.delegate = self
pickerView.dataSource = self
}
//pickerの列の数を決めます。
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
//pickerの行数を決めます。
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return cityList.list.count
}
//pickerに表示するデータを決めます。
//ここでは取得したmodelのデータのnameを表示します。
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return cityList.list[row].name
}
//選択時の挙動を決めます。
//次の画面に渡すために、取得したmodelのデータから、codeとnameを変数に入れます。
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
cityData = [cityList.list[row].code,cityList.list[row].name]
}
//ボタン押した時の処理を書きます。画面遷移です。
@IBAction func resultButton(_ sender: Any) {
performSegue(withIdentifier: "result", sender: nil)
}
//次の画面にデータを渡す処理を書きます。
//prepareは、segueが動作するとViewControllerに通知してくれます。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "result" {
//resultViewController(次の画面)で作った変数に、pickerで選択した地域の情報を入れます。
let resultVC = segue.destination as! ResultViewController
resultVC.cityData = cityData
}
}
}
次の画面を実装します。
この画面では、天気予報の取得とラベルに反映を行います。
import UIKit
//Podからインスールしたライブラリを使うのでインポートします。
import Alamofire
import SwiftyJSON
//componentsを使用するのでインポートします。
import Foundation
class ResultViewController: UIViewController {
@IBOutlet weak var cityNameLabel: UILabel!
@IBOutlet weak var detailsTextView: UITextView!
@IBOutlet weak var todayDateLabel: UILabel!
@IBOutlet weak var todayWeatherLabel: UILabel!
@IBOutlet weak var todayHighLabel: UILabel!
@IBOutlet weak var todayLowLabel: UILabel!
@IBOutlet weak var tomorrowDateLabel: UILabel!
@IBOutlet weak var tomorrowWeatherLabel: UILabel!
@IBOutlet weak var tomorrowHighLabel: UILabel!
@IBOutlet weak var tomorrowLowLabel: UILabel!
let highString = "最高気温:"
let lowString = "最低気温:"
//取得した天気予報のデータを入れます。
var date:String = ""
var weather:String = ""
var high:String = ""
var low:String = ""
var details:[String] = []
//ViewController(前の画面)に渡し、選択した地域のデータを入れます。
var cityData:[String] = []
override func viewDidLoad() {
super.viewDidLoad()
getWeatherData(row: 0)
getWeatherData(row: 1)
}
//天気情報を取得する。
private func getWeatherData(row: Int) {
//前の画面から渡されたデータのcodeを、urlに組み込みます。
let url = "http://weather.livedoor.com/forecast/webservice/json/v1?city=\(cityData[0])"
//Alamofireで通信します。データを取得します。
AF.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default).responseJSON {(response) in
switch response.result {
case .success:
//jsonを取得します。
let json:JSON = JSON(response.data as Any)
//取得したjsonから、必要なデータを取り出します。
let date = json["forecasts"][row]["date"].string
let weather = json["forecasts"][row]["telop"].string
let high = json["forecasts"][row]["temperature"]["max"]["celsius"].string
let low = json["forecasts"][row]["temperature"]["min"]["celsius"].string
let details = json["description"]["text"].string
//取り出したデータを、それぞれの変数に入れます。
//データがない場合もあるので、その時は"No Data"と入れておきます。
if date != nil {
self.date = String(date!.suffix(5)) //2025-04-10 -> 04-10
} else {
self.date = "No Data"
}
if weather != nil {
self.weather = weather!
} else {
self.weather = "No Data"
}
if high != nil {
self.high = "\(high!)°"
} else {
self.high = "No Data"
}
if low != nil {
self.low = "\(low!)°"
} else {
self.low = "No Data"
}
if details != nil {
self.details = (details?.components(separatedBy: .newlines))! //改行で分割します。
} else {
self.details = ["No Details"]
}
//ラベルに反映させます。
self.setWeatherData(row: row)
case .failure(let error):
print("-------- エラー ------")
print(error)
}
}
}
//ラベルに反映させる処理です。
//引数を与えて、todayとtomorrowで分岐させます。
private func setWeatherData(row: Int) {
if row == 0 {
todayWeatherLabel.text = weather
todayDateLabel.text = date
todayHighLabel.text = highString + high
todayLowLabel.text = lowString + low
//分割時に配列になっているので、1つ目の要素だけ表示します。
detailsTextView.text = details[0]
} else if row == 1 {
tomorrowWeatherLabel.text = weather
tomorrowDateLabel.text = date
tomorrowHighLabel.text = highString + high
tomorrowLowLabel.text = lowString + low
}
}
}
コードの内容はさておき、天気予報のデータの取得に成功しました。
ViewDidLoad内でフォントサイズやボタンの枠線を変更していますが、
長くなるので割愛しました。お好みでどうぞ。