iOS Dev. Lesson 10
iOS Dev. Lesson 10
Agenda
- Put all weather data fetching into Weather.swift
- Showing cities in Map View
- Showing external website with SFSafariController
Weather.swift
struct WeatherService {
// 3 functions here
}
struct WeatherService {
public func fetchCurrentWeather( completion: ((Weather) -> Void)? = nil) {
guard let url = URL(string: "https://dev.makzan.net/weather.json") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if error != nil {
print(error!)
return
}
do {
let json = try JSONDecoder().decode(Weather.self, from: data)
completion?(json)
} catch let error{
print("Fetch error.")
print(error)
}
}.resume()
}
// 2 more functions here
}
What is
completion function parameter?
struct WeatherService {
public func fetchCurrentWeather( completion: ((Weather) -> Void)? = nil) {
//...
completion?(json)
//...
}
// 2 more functions here
}
public func hello( completion: ((String)->Void)?=nil) {
completion?("Result Here")
}
struct WeatherService {
public func fetchCurrentWeather( completion: ((Weather) -> Void)? = nil) {
guard let url = URL(string: "https://dev.makzan.net/weather.json") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if error != nil {
print(error!)
return
}
do {
let json = try JSONDecoder().decode(Weather.self, from: data)
completion?(json)
} catch let error{
print("Fetch error.")
print(error)
}
}.resume()
}
public func fetchForecastWeather( completion: (([ForecastDay]) -> Void)? = nil) {
guard let url = URL(string: "https://dev.makzan.net/weather.json") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if error != nil {
print(error!)
return
}
do {
let json = try JSONDecoder().decode(Forecast.self, from: data)
completion?(json.forecasts)
} catch let error{
print("Fetch error.")
print(error)
}
}.resume()
}
// 1 more function here
}
struct WeatherService {
public func fetchCurrentWeather( completion: ((Weather) -> Void)? = nil) {
guard let url = URL(string: "https://dev.makzan.net/weather.json") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if error != nil {
print(error!)
return
}
do {
let json = try JSONDecoder().decode(Weather.self, from: data)
completion?(json)
} catch let error{
print("Fetch error.")
print(error)
}
}.resume()
}
public func fetchForecastWeather( completion: (([ForecastDay]) -> Void)? = nil) {
guard let url = URL(string: "https://dev.makzan.net/weather.json") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if error != nil {
print(error!)
return
}
do {
let json = try JSONDecoder().decode(Forecast.self, from: data)
completion?(json.forecasts)
} catch let error{
print("Fetch error.")
print(error)
}
}.resume()
}
public func fetchCitiesWeather( completion: (([CityWeather]) -> Void)? = nil) {
guard let url = URL(string: "https://dev.makzan.net/cities_weather.json") else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
if error != nil {
print(error!)
return
}
do {
let json = try JSONDecoder().decode(CitiesWeather.self, from: data)
completion?(json.cities)
} catch let error{
print("Fetch error.")
print(error)
}
}.resume()
}
// 1 more function here
}
struct Weather:Decodable {
var date: String = ""
var temperature: String = ""
var humidity: String = ""
var windSpeed: String = ""
var windDescription: String = ""
var today:String = ""
var statusCode:String = ""
var todayDescription = ""
var tomorrowDescription = ""
}
struct Forecast:Decodable {
var forecasts: [ForecastDay] = []
}
struct ForecastDay:Decodable {
var date:String = ""
var statusCode:String = ""
var temperatureLow:String = ""
var temperatureHigh:String = ""
var description:String = ""
}
struct CitiesWeather:Decodable {
var cities: [CityWeather] = []
}
struct Coordinate:Decodable {
var latitude: Double
var longitude: Double
}
struct CityWeather:Decodable {
var cityName:String = ""
var date:String = ""
var temperatureLow:String = ""
var temperatureHigh:String = ""
var description:String = ""
var coordinate:Coordinate
}
struct StatusCode {
// https://xml.smg.gov.mo/#Status
static let statusCodes = [
"01": "sun.max.fill",
"a1": "moon.fill",
"02": "cloud.sun.fill",
"a2": "cloud.moon.fill",
"03": "cloud.fill",
"04": "cloud.fill",
"12": "cloud.rain.fill",
"13": "cloud.rain.fill",
"16": "cloud.heavyrain.fill",
"17": "cloud.heavyrain.fill",
"18": "cloud.bolt.rain.fill",
"25": "cloud.bolt.fill",
"27": "cloud.rain.fill",
"28": "cloud.rain.fill",
"c8": "cloud.moon.rain.fill",
"29": "cloud.rain.fill",
"c9": "cloud.moon.rain.fill",
]
static func symbolFor(statusCode:String) -> String {
return statusCodes[statusCode] ?? "sun.fill"
}
}
Map View
CitiesMapViewController
import MapKit
import UIKit
import MapKit
class CitiesMapViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView!
var cities: [CityWeather] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let coordinate = CLLocationCoordinate2D(latitude: 32.59037534587093, longitude: 114.95212987586083)
// 5,000KM x 3,000KM
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 5000*1000, longitudinalMeters: 3000*1000)
mapView.setRegion(region, animated: false)
// fetch cities weather
WeatherService().fetchCitiesWeather { (cities) in
self.cities = cities
DispatchQueue.main.async {
self.renderCities()
}
}
}
func renderCities() {
var annotations: [MKAnnotation] = []
for city in cities {
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: city.coordinate.latitude, longitude: city.coordinate.longitude)
annotation.title = city.cityName
annotation.subtitle = "\(city.temperatureLow)—\(city.temperatureHigh) \(city.description)"
annotations.append(annotation)
}
mapView.addAnnotations(annotations)
}
}
SFSafariController
import SafariServices
@IBAction func tapDetails(_ sender: Any) {
guard let url = URL(string: "https://www.smg.gov.mo/") else {
return
}
let vc = SFSafariViewController(url: url)
self.show(vc, sender: false)
}
deck
By makzan
deck
- 364