Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Build a Weather App with Swift (Retired) Displaying Our Weather Data The End!

Mohsen Lotfi
Mohsen Lotfi
2,694 Points

How to get current location on ViewDidLoad

I think I finally figured out the location challenge, However, on Xcode and when debugging, location value gets update only if I click refresh button. before that I am getting 0.0 (initial value) for both lat and long

Would appreciate any feedback on this

here is my code

import UIKit
import CoreLocation


class ViewController: UIViewController,CLLocationManagerDelegate {


    @IBOutlet weak var iconView: UIImageView!
    @IBOutlet weak var currentTimeLabel: UILabel!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var humadityLabel: UILabel!
    @IBOutlet weak var precipitationLabel: UILabel!
    @IBOutlet weak var summaryLabel: UILabel!
    @IBOutlet weak var refreshActivityIndicator: UIActivityIndicatorView!
    @IBOutlet weak var refreshButton: UIButton!

    private let apiKey = "#################"

    let locationManager = CLLocationManager()
    var locationLat: Double = 0
    var locationLong: Double = 0


    override func viewDidLoad() {

        super.viewDidLoad()

        getCurrentWeatherData()


        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.requestAlwaysAuthorization()
        if (CLLocationManager.locationServicesEnabled())
        {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            locationManager.requestAlwaysAuthorization()
            locationManager.startUpdatingLocation()
        }

        //Print out location after viewDidLoad()
        println("on viewDidLoad Location is \(locationLat) and \(locationLong)")

        refreshActivityIndicator.hidden = true

        super.viewDidLoad()
    }

     func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        var locValue:CLLocationCoordinate2D = manager.location.coordinate

        locationLat = locValue.latitude
        locationLong = locValue.longitude
        }

    func getCurrentWeatherData() -> Void {

        var currentLat = locationLat
        var CurrentLon = locationLong

        //printout Location inside function
        println("inside func location is \(currentLat) and \(CurrentLon)")

        let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
        let forecastURL = NSURL(string: "\(currentLat),\(CurrentLon)/", relativeToURL:baseURL!)
        let sharedSession = NSURLSession.sharedSession()
        let downloadTask : NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location :NSURL!, response: NSURLResponse!, error: NSError!) -> Void in

            if (error == nil) {
                let dataObject = NSData(contentsOfURL: location)
                let weatherDictionary: NSDictionary  = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as NSDictionary
                let currentWeather = Current(weatherDictionary: weatherDictionary)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.temperatureLabel.text = "\(currentWeather.temprature)"
                    self.iconView.image = currentWeather.icon!
                    self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
                    self.humadityLabel.text = "\(currentWeather.humadity)"
                    self.precipitationLabel.text = "\(currentWeather.precipProbability)"
                    self.summaryLabel.text = "\(currentWeather.summary)"

                    // stop refresh process
                    self.refreshActivityIndicator.stopAnimating()
                    self.refreshActivityIndicator.hidden = true
                    self.refreshButton.hidden = false
                })
            } else {
                let networkIssueController = UIAlertController(title: "Ooops", message: "Something went seriously wrong!...Nope, Just enable WiFi Again" , preferredStyle: .Alert)
                self.presentViewController(networkIssueController, animated: true, completion: nil)
                let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
                networkIssueController.addAction(okButton)
                let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
                networkIssueController.addAction(cancelButton)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                    self.refreshActivityIndicator.stopAnimating()
                    self.refreshActivityIndicator.hidden = true
                    self.refreshButton.hidden = false
                })
                }
        })

        downloadTask.resume()
    }

    @IBAction func refresh() {
        refreshButton.hidden = true
        refreshActivityIndicator.hidden = false
        refreshActivityIndicator.startAnimating()
        getCurrentWeatherData()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
}


}

here is the println console output

inside func location is 0.0 and 0.0
on viewDidLoad Location is 0.0 and 0.0
inside func location is 35.7020691 and 139.7753269

3 Answers

Mohsen Lotfi
Mohsen Lotfi
2,694 Points

o.k I I figured it out, here is the answer if anyone is interested, needed to add these two bad boys in viewDidLoad

        locationLat = locationManager.location.coordinate.latitude
        locationLong = locationManager.location.coordinate.longitude

Now you need to be careful with this as it might cause a runtime error since apparently it can take couple of seconds to get the location update from GPS and this might return nil. to prevent it you can add optional unwrapping and repeat the process to get a value.

As a bonus, following is also reverse geodecoder that I added to get the location based on current coordinates. Shoutout to whoever I copied it from (SO post I guess)

var location = CLLocationManager()



        CLGeocoder().reverseGeocodeLocation(location.location, completionHandler: {(placemarks, error) -> Void in

            if error != nil {
                println("Reverse geocoder failed with error" + error.localizedDescription)
                return
            }

            if placemarks.count > 0 {
                let pm = placemarks[0] as CLPlacemark

//Printing to console to check value! 
                println("\(pm.locality)")
                println("\(pm.subLocality)")

                self.locality = pm.locality as String
                if ( pm.subLocality != nil) {

                    self.subLocality = pm.subLocality as String
                }
            }
            else {
                println("Problem with the data received from geocoder")
            }
        })
Brian Patterson
Brian Patterson
19,588 Points

Im struck on the UIAlertView. As this has been deprecated . How do you add the UIAlertViewController? Well done on getting the current location.

Jared Watkins
Jared Watkins
10,756 Points

Thanks for sharing your code.

This didn't work for me. The original values for locationLat and locationLong never change from 0. And the authorization requests aren't ever triggered triggered.

   self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.requestAlwaysAuthorization()
        if (CLLocationManager.locationServicesEnabled())
        {
            locationManager.delegate = self.locationManager.delegate
            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            locationManager.requestAlwaysAuthorization()
            locationManager.startUpdatingLocation()

Also, I can't see that the locationManager() function is ever called or doing anything.

 func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        var locValue:CLLocationCoordinate2D = manager.location.coordinate

        locationLat = locValue.latitude
        locationLong = locValue.longitude
        }
Mohsen Lotfi
Mohsen Lotfi
2,694 Points

Previous code was intended to show how to get the location on viewDidLoad, it certainly has some performance and bugs that I still trying to find my way around it. This is the latest improvements. Hope it works for you. Also about the location being 0, As far as I can tell it has to do something with the iOS simulator, for some reason, simulator starts updating location couple of second after the initial viewDidLoad and such cases results in nil as location which can crash the application.

My work around for this was to check and see if the location is either 0 or nil and then restart "start location update". this seems to help with the issue.

import UIKit
import CoreLocation
import SystemConfiguration

class ViewController: UIViewController,CLLocationManagerDelegate {

    @IBOutlet weak var iconView: UIImageView!
    @IBOutlet weak var currentTimeLabel: UILabel!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var humadityLabel: UILabel!
    @IBOutlet weak var precipitationLabel: UILabel!
    @IBOutlet weak var summaryLabel: UILabel!
    @IBOutlet weak var refreshActivityIndicator: UIActivityIndicatorView!
    @IBOutlet weak var refreshButton: UIButton!
    @IBOutlet weak var locationLabel: UILabel!
    @IBOutlet weak var subLocationLabel: UILabel!

    private let apiKey = "#####################"

    let locationManager = CLLocationManager()

    var locationLat: Double = 0
    var locationLong: Double = 0
    var locality: String = ""
    var subLocality:String = ""
    var refershController  = UIRefreshControl()
    override func viewDidLoad() {
        super.viewDidLoad()

        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.requestAlwaysAuthorization()
//        if (CLLocationManager.locationServicesEnabled())

            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
            locationManager.requestAlwaysAuthorization()
            locationManager.startUpdatingLocation()
            locationManager.distanceFilter = 100

        if locationManager.location != nil {
            locationLat = locationManager.location.coordinate.latitude
            locationLong = locationManager.location.coordinate.longitude

            refresh()
        }

//            Else below is a duplicate and does not require to be here. It is just extra debug level for observation
        else
        {


            println("Location is Nil ")
            refreshActivityIndicator.hidden = true

            refresh()




            func LocationManagers(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {


                locationLat = manager.location.coordinate.latitude
                locationLong = manager.location.coordinate.longitude

                refresh()
            }


        }

        refreshActivityIndicator.hidden = true
        refresh()
        super.viewDidLoad()
    }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        var locValue:CLLocationCoordinate2D = manager.location.coordinate
        var currentLocation = CLLocation()

        self.locationLat = locValue.latitude
        self.locationLong = locValue.longitude





    }

//     func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
//        println("error + " + error.localizedDescription)
//    }
    func getCurrentWeatherData() -> Void {

        let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
        let forecastURL = NSURL(string: "\(locationLat),\(locationLong)/",
            relativeToURL:baseURL!)

        let sharedSession = NSURLSession.sharedSession()
        let downloadTask : NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location :NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
            if (error == nil) {

                self.refreshButton.hidden = true
                self.refreshActivityIndicator.hidden = false
                self.refreshActivityIndicator.startAnimating()

                let dataObject = NSData(contentsOfURL: location)
                let weatherDictionary: NSDictionary  = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as NSDictionary
                let currentWeather = Current(weatherDictionary: weatherDictionary)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                    self.temperatureLabel.text = "\(currentWeather.temprature)"
                    self.iconView.image = currentWeather.icon!
                    self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
                    self.humadityLabel.text = "\(currentWeather.humadity)"
                    self.precipitationLabel.text = "\(currentWeather.precipProbability)"
                    self.summaryLabel.text = "\(currentWeather.summary)"

                    // stop refresh process
                    self.refreshActivityIndicator.stopAnimating()
                    self.refreshActivityIndicator.hidden = true
                    self.refreshButton.hidden = false
                    self.locationLabel.text = "\(self.locality)"
                    self.subLocationLabel.text =  "\(self.subLocality)"
                })
            } else {
                let networkIssueController = UIAlertController(title: "Ooops", message: "Something went seriously wrong!...Nope, Just enable WiFi Again" , preferredStyle: .Alert)
                self.presentViewController(networkIssueController, animated: true, completion: nil)
                let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
                networkIssueController.addAction(okButton)
                let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
                networkIssueController.addAction(cancelButton)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in

                    self.refreshActivityIndicator.stopAnimating()
                    self.refreshActivityIndicator.hidden = true
                    self.refreshButton.hidden = false
                })
            }
        })
        downloadTask.resume()

    }
@IBAction func refresh()



    {


        if IJReachability.isConnectedToNetwork() {

            refreshButton.hidden = true
            refreshActivityIndicator.hidden = false
            refreshActivityIndicator.startAnimating()
            if  locationManager.location != nil {
//                
//            self.locationLat = locationManager.location.coordinate.latitude
//            self.locationLong = locationManager.location.coordinate.longitude
//            
            CLGeocoder().reverseGeocodeLocation(locationManager.location, completionHandler: {(placemarks, error) -> Void in
                    if error != nil {

                        println("Reverse geocoder failed with error" + error.localizedDescription)
                        self.refresh()}
                    if placemarks.count > 0 {
                        let pm = placemarks[0] as CLPlacemark
                        self.locality = pm.locality as String
                        if ( pm.subLocality != "") {
                            self.subLocality = pm.subLocality as String}
                        println("First XXXXGeo \(pm.subLocality)")
                        self.getCurrentWeatherData()
                    }
                    else {
                        self.locationManager.startUpdatingLocation()
                        self.refresh()
                        println("Problem with the data received from geocoder")}
                })
            }

            else {
                self.locationManager.startUpdatingLocation()
                println("\(locationLat)")
                refresh()
            }
        } else {

            self.locationManager.startUpdatingLocation()
            println("no Network ")

            let networkConnectionController = UIAlertController(title: "No Internet Connectin", message: "This app needs Internet connection to work, Hit refresh to retry" , preferredStyle: .Alert)
            self.presentViewController(networkConnectionController, animated: true, completion: nil)
            let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
            networkConnectionController.addAction(okButton)
            let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
            networkConnectionController.addAction(cancelButton)

            }

    }


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


}

Also I found this on internet (original post http://www.chrisdanielson.com/2009/07/22/iphone-network-connectivity-test-example/) , which does a great job checking for internet connection before the app starts and is a bit more advanced than the one mentioned in the course.