4
\$\begingroup\$

I'm learning Swift at the moment but I would like to produce well-organised code. The goal of my little app is to display the weather of my current location.

I use :

  • the API of Darksky : https://darksky.net/dev for fetching the forecast data
  • the Reverse Geocoding With CLGeocoder for fetching the city's name of the current coordinate

I would like to improve my main controller and if possible the user experience, let me explain:

In the controller, once I have the coordinate (thanks to the class CLLocationManager), I call my two functions for getting the forecast information AND the city's name.

I have default values in my storyboard that are replaced once I fetched the data. Ideally I would like to update my UI only when I have all data.

import UIKit
import CoreLocation

    class ForecastViewController: UIViewController {

        // MARK: IBOulets

        @IBOutlet weak var temperatureLabel: UILabel!
        @IBOutlet weak var cityNameLabel: UILabel!
        @IBOutlet weak var unitLabel: UILabel!

        // MARK: Properties

        var forecastResponse = ForecastResponse(json: [:]) {
            didSet {
                self.updateTemperatureUI()
            }
        }

        var city: String? {
            didSet {
                self.updateLocaltionUI()
            }
        }

        var coordinate: Coordinate? {
            didSet {
                print("Coordinate has been set")
                self.getCurrentForecast()
                self.getCurrentLocation()
            }
        }

        let secretKey = "123"
        let language = "fr"
        let units = "si"

        var darkskyClient: DarkskyClient!
        let locationManager = LocationManager()
        lazy var geocoder = CLGeocoder()

        override func viewDidLoad() {

            super.viewDidLoad()

            self.darkskyClient = DarkskyClient(secretKey: self.secretKey)

            // Location Service
            self.locationManager.getPermission()
            self.locationManager.didGetLocation = { [weak self] coordinate in
                self?.coordinate = coordinate
            }

            getCurrentLocation()
            getCurrentForecast()

        }

        // MARK: Geocoding Handler

        func processGeocodingResponse(withPlacemarks placemarks: [CLPlacemark]?, error: Error?) {

            if let error = error {
                print("Unable to Reverse Geocode Location (\(error))")
            } else {
                if let placemarks = placemarks, let placemark = placemarks.first, let city = placemark.locality {
                    self.city = city
                } else {
                    self.city = "No Matching City Found"
                }
            }
        }

        // MARK: Private methods

        private func getCurrentForecast() {
            if let coordinate = self.coordinate {
                self.darkskyClient.fetcthCurrentForecast(coordinate: coordinate, lang: self.language, units: self.units, completion: { (result) in
                    switch result {
                    case .success(let forecastResponse):
                        self.forecastResponse = forecastResponse
                    case .failure(let error):
                        print(error)
                    }
                })
            }
        }

        private func getCurrentLocation() {
            if let coordinate = self.coordinate {

                // Create Location
                let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)

                // Geocode Location
                geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
                    // Process Response
                    self.processGeocodingResponse(withPlacemarks: placemarks, error: error)
                }
            }
        }

        private func updateTemperatureUI() {
            if let temperatureInCelsiusDegress = self.forecastResponse?.currently?.temperature,
                let unitName = TemperatureUnitHelper(rawValue: self.units)?.path {
                self.temperatureLabel.text = "\(Int(temperatureInCelsiusDegress))"
                self.unitLabel.text = unitName.uppercased()
            }
        }

        private func updateLocaltionUI() {
            self.cityNameLabel.text = self.city
        }
    }

What kind of improvements can I do ? and tell me of course what I've done wrong in my controller.

\$\endgroup\$
  • \$\begingroup\$ If your intention is to update UI after both the API requests are completed check Dispatch Groups. \$\endgroup\$ – GoodSp33d Oct 11 '17 at 8:31
  • \$\begingroup\$ @GoodSp33d thanks for your comment after I checked, it seems to fit with my needs. I'll post an answer if I manage to implement it :) \$\endgroup\$ – Adrien G Oct 11 '17 at 8:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.