Beginners have created a portfolio for both learning and portfolio. It's been about 1 to 2 months since I started creating it, so I would like advice on refactoring and coding.
If you are a salaried worker, I thought it would be convenient if there was an app that could instantly check if you needed an umbrella today.
I press the button ↓ Determine the latitude and longitude of your current location from GPS ↓ Reverse geocoding from latitude / longitude ↓ Determine the prefecture you are in ↓ Determining the probability of precipitation in the prefecture you are in from the weather API ↓ Show if you need an umbrella or not
Such an app had already been released, but it wasn't the one I wanted, so I also tried to create a portfolio.
Target | version |
---|---|
iOS | 14.0 |
macOS | Catalina 10.15.7 |
Xcode | 12.0 |
Swift | 5.3 |
Weather API used OpenWeatherMap
This time I have installed "Alaomofire" and "SwiftyJSON".
Podfile
pod "Alamofire"
pod "SwiftyJSON"
Main.storyboad
This time I created HomeVC and UmbrellaVC. Move to Home VC after launching the app → Tap the "Location Information" button → Move to Umbrella VC ① For label, call the prefecture of your current location obtained by reverse geocoding. ② For label, call the probability of precipitation at your current location from the weather API. ③ For label, judge whether an umbrella is necessary or not from the probability of precipitation
First, create a model of the data to be acquired by the weather API.
CityModel.swift
import Foundation
struct cityModel:Decodable{
var list: [List]
struct List:Decodable {
var pop:Double
}
}
I think that the structure described here depends on the API data to be acquired. In the weather API "OpenWeather" used this time, the above acquisition was obtained.
The numerical value of the item "pop" in this is the numerical value to be acquired this time (Double type)
UmbrellaVC.swift
import UIKit
import CoreLocation
class UmbrellaVC: UIViewController {
@IBOutlet weak var label1: UILabel!
var locationText:String = "Osaka"
@IBOutlet weak var label2: UILabel!
var popText:Int = 0
@IBOutlet weak var label3: UILabel!
var umbrellaJudgement:String = "I need an umbrella"
override func viewDidLoad() {
super.viewDidLoad()
label1.text = locationText
label2.text = "\(popText)" + "%"
label3.text = umbrellaJudgement
self.label3.layer.borderWidth = 2.0
self.label3.layer.borderColor = UIColor.black.cgColor
self.label3.layer.cornerRadius = 20
//Change the color of the letters that appear according to the probability of precipitation so that you can see at a glance
if popText >= 30{
label3.textColor = .orange
}else if popText >= 70{
label3.textColor = .red
}
}
}
Assign to the variable set in UmbrellaVC.
HomeVC.swift
import UIKit
import CoreLocation
import Alamofire
import SwiftyJSON
class HomeVC: UIViewController,CLLocationManagerDelegate {
//Put the initial value in each variable
var latitudeNow: Double = 39.0000
var longitudeNow: Double = 140.0000
var locationManager: CLLocationManager!
var administrativeArea:String = ""
var locationNow: String = ""
private var citymodel: cityModel?
var doubleOfMaximumPop:Double = 100.0
var maxPop:Int = 30
var Judge:String = ""
override func viewDidLoad() {
super.viewDidLoad()
//Image view layout settings
umbrellaImage.image = UIImage(named:"umbrellaImage")
umbrellaImage.layer.cornerRadius = 10
//Call locationManager at viewDidload (update location information)
locationManagerDidChangeAuthorization(CLLocationManager())
//Calling the weather acquisition function
getWeatherData()
}
//Get location information when you press a button
@IBAction func buttonTapped(_ sender: Any) {
//Press the button to stop updating locationManager
stopLocationManager()
}
//Press the button to switch to segue and list the prefecture in Label 1 in Umbrella VC.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "toUmbrellaVC") {
let locationNow: UmbrellaVC = (segue.destination as? UmbrellaVC)!
locationNow.locationText = administrativeArea
let popNow:UmbrellaVC = (segue.destination as? UmbrellaVC)!
popNow.popText = Int(maxPop)
let umbJud:UmbrellaVC = (segue.destination as? UmbrellaVC)!
umbJud.umbrellaJudgement = Judge
}
}
//Location manager @ iOS 14 Update location information
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
locationManager = CLLocationManager()
let status = manager.authorizationStatus
switch status {
case .authorizedAlways, .authorizedWhenInUse:
locationManager.delegate = self
locationManager.startUpdatingLocation()
case .notDetermined, .denied, .restricted:
showAlert()
default:print("Untreated")
}
}
//Stop updating locationManager information
func stopLocationManager(){
locationManager.stopUpdatingLocation()
}
//Function to display alerts
func showAlert(){
let alertTitle = "Location information acquisition is not permitted."
let alertMessage = ""Privacy" of the setting app>Please change from "Location services"."
let alert: UIAlertController = UIAlertController(
title: alertTitle, message: alertMessage, preferredStyle: UIAlertController.Style.alert
)
//OK button
let defaultAction: UIAlertAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil)
//Added Action to UIAlertController
alert.addAction(defaultAction)
present(alert, animated: true, completion: nil)
}
//Function to store location information when location information is updated
//Location manager will not start unless location information is updated * Important
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.first
let latitude = location!.coordinate.latitude
let longitude = location!.coordinate.longitude
//Store location information
self.latitudeNow = Double(latitude)
self.longitudeNow = Double(longitude)
//After acquiring the location information, reverse geocode it to determine the prefecture.
let locationA = CLLocation(latitude: latitudeNow, longitude: longitudeNow)
let geocoder: CLGeocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(locationA) { [self](placemarks, error) in
if let placemark = placemarks?.first {
self.administrativeArea = placemark.administrativeArea!
} else {
self.administrativeArea = "bb"
}
}
}
//Get the maximum precipitation probability up to 18 hours later using the weather forecast API
//In OpenWeatherMap, there is a charge for acquiring the probability of precipitation for one day, and it is free to acquire the probability of precipitation every three hours, so use that(I assumed that I would see it before going to work in the morning, so I judged that there was no problem)
private func getWeatherData() {
let id = "Enter API ID"
let baseUrl = "http://api.openweathermap.org/data/2.5/forecast?lat=" + "\(latitudeNow)" + "&lon=" + "\(longitudeNow)" + "&exclude=daily&lang=ja&cnt=6&.pop&appid=" + "\(id)"
AF.request(baseUrl, method: .get).responseJSON { [self] response in
guard let data = response.data else {
return
}
do {
let citymodel = try JSONDecoder().decode(cityModel.self, from: data)
//List API data
let popNumber = citymodel.list.map{ $0.pop }
//Get max data in list
var doubleOfMaximumPop = popNumber.max()
//Convert to percentage display of max data
let maxPop = doubleOfMaximumPop! * 100
//Determine if there is data
if doubleOfMaximumPop == nil{
print(Error.self)
}else {
//If you have the data
if doubleOfMaximumPop != nil{
//get max data
doubleOfMaximumPop = self.doubleOfMaximumPop
}else {
//If the numbers are the same, pick one of them
doubleOfMaximumPop = popNumber[0]
}
}
//Assign the numerical value obtained by the getweather function to maxPop to the variable
self.maxPop = Int(maxPop)
//Judge whether an umbrella is necessary by maxPop, and substitute the judged sentence into Judge.
if self.maxPop <= 30 {
self.Judge = "⛅️ No umbrella required ⛅️"
}else if self.maxPop >= 70 {
self.Judge = "☔️ I need an umbrella ☔️"
}else {
self.Judge = "☂️ Peace of mind if you have a folding umbrella ☂️"
}
}catch let error {
print("Error:\(error)")
}
}
}
}
It's not readable because you don't really know what the variable name stands for ... Variable name is difficult ...
-Since I did not understand the flow of updating location information with LocationManager → reverse geocoding to acquire data, problems such as data being acquired but not being assigned to variables occurred.
Core Location changes in iOS 14 Assign variables inside the function to variables outside the function [Notes about Codale] (https://qiita.com/s_emoto/items/deda5abcb0adc2217e86)
Many people have posted the source code on Qiita, so I was able to create it so far, so I created it with the hope that it would be useful for people in similar circumstances.
Recommended Posts