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!

How can I pass the latitude and longitude data from CLLocationManager delegate to forecastURL

//
//  ViewController.swift
//  My Weather
//
//

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {


    @IBOutlet weak var iconLabel: UIImageView!
    @IBOutlet weak var currentTimeLabel: UILabel!
    @IBOutlet weak var temperatureLabel: UILabel!
    @IBOutlet weak var humidityLabel: UILabel!
    @IBOutlet weak var precipitationLabel: UILabel!
    @IBOutlet weak var summaryLabel: UILabel!
    @IBOutlet weak var refreshButton: UIButton!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    var locationManager: CLLocationManager!
    var geoCoder : CLGeocoder!
    var placemark : CLPlacemark!

    var latitude : String!
    var longitude : String!


    private let apiKey = "a6c333308f623f3118bd566ee78d159c"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.activityIndicator.hidden = true;
        self.getCurrentWeatherData()

        self.locationManager = CLLocationManager()
        locationManager.requestAlwaysAuthorization()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startMonitoringSignificantLocationChanges()

        geoCoder = CLGeocoder()
        placemark = CLPlacemark()

    }

    func getCurrentWeatherData() -> Void {

//        println("longitude \(latitude)")
//        println("latitude \(longitude)")

        let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
        let forecastURL = NSURL(string:"3.0920,101.4943?units=si", 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.dataWithContentsOfURL(location, options: nil, error: nil)
                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.iconLabel.image = currentWeather.icon!
                    self.currentTimeLabel.text = currentWeather.currentTime!
                    self.temperatureLabel.text = "\(currentWeather.temperature)"
                    self.humidityLabel.text = "\(currentWeather.precipProbability)"
                    self.summaryLabel.text = currentWeather.summary

                    // Stop refresh animation
                    self.activityIndicator.stopAnimating()
                    self.activityIndicator.hidden = true
                    self.refreshButton.hidden = false
                })

            }

            else {

                let networkIssueAlert = UIAlertController(title: "Network Error", message: "Please connected to the internet to get latest weather data", preferredStyle: .Alert)
                let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
                networkIssueAlert.addAction(okButton)
                let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
                networkIssueAlert.addAction(cancelButton)
                self.presentViewController(networkIssueAlert, animated: true, completion: nil)

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

                    // Stop refresh animation
                    self.activityIndicator.stopAnimating()
                    self.activityIndicator.hidden = true
                    self.refreshButton.hidden = false
                })

            }
        })

        downloadTask.resume()

    }



    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        println("error to get location : \(error)")
    }



    func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {

        let currentLocation : CLLocation = newLocation


            latitude = "\(currentLocation.coordinate.latitude)"
            longitude = "\(currentLocation.coordinate.longitude)"
            println("longitude \(self.latitude)")
            println("latitude \(self.longitude)")


    }



    @IBAction func refresh(sender: AnyObject) {

        self.getCurrentWeatherData()
        self.refreshButton.hidden = true
        self.activityIndicator.hidden = false
        self.activityIndicator.startAnimating()

    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

I succesfully got the latitude and longitude in CLLocationManagerDelegate but how can i reuse latitude and longitude variable in let forecastURL = NSURL(string:"3.0920,101.4943?units=si", relativeToURL: baseURL). Please someone help me. Pasan Premaratne Amit Bijlani

5 Answers

Kieran Robinson
Kieran Robinson
9,411 Points

Assuming you have both the latitude and longitude stored in NSStrings, i just used this string as the URL

let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/\(LatitudeForWeather),\(longitudeForWeather)")

which should work, let me know if you need help

Daniel Wendt
Daniel Wendt
1,911 Points

hi mamat golo hi Kieran Robinson

did you solve the problem in the meantime?

cause i have the same problem right now....

i can print the Latitude & Longitude in the function as a String but when i want to call it in the URL it always say "nil" so the func getCurrentWeatherData didn't know the 2 strings.

But the GPS location for it self works, i can simulate every city on the planet. The Data is fine....

Hope some on can help me :)

TANKS!

here is the relevant code:

func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        let currentLocation : CLLocation = newLocation

        latitude = "\(currentLocation.coordinate.latitude)"
        longitude = "\(currentLocation.coordinate.longitude)"

        println("Hier stehen die GeoDaten der neuen Stadt\(latitude),\(longitude)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Function!!!!!!")
    }
    //----------------------------------GPS-------------------------------------------

    func getCurrentWeatherData() -> Void {

        let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
        //let forecastURL = NSURL(string: "54.833017,9.564135", relativeToURL: baseURL)
        let forecastURL = NSURL(string: "\(latitude),\(longitude)", relativeToURL: baseURL)


        println(forecastURL)



        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

.....

Console :

Optional(nil,nil -- https://api.forecast.io/forecast/ee1eeece9cb46135aabb59ed24327bf0/)

fatal error: unexpectedly found nil while unwrapping an Optional value

Justin Bane
Justin Bane
7,850 Points

I have this exact same issue... has anyone solved this. I have looked all over and it just doesnt work. I can get coordinates all day long... if I try to pass them as a string into the forecastURL variable I get the same - fatal error: unexpectedly found nil while unwrapping an Optional value

ANYONE HELP! - really wish the course had gone a bit deeper into the working of the classes and phone capability - this was basically a beginning programming course.

Chad Goodyear
Chad Goodyear
9,634 Points

Just a heads up because I was working on this yesterday and it was driving me mad and I saw you are using: ``` geoCoder = CLGeocoder() placemark = CLPlacemark()

so I guess you are converting the GPS location to english to update a 'location' label somewhere. It may be that part that is giving you the error - even thought your code* is fine!

from the CLGeocoder documentation: "Applications should be conscious of how they use geocoding. Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may cause some of the requests to fail. (When the maximum rate is exceeded, the geocoder returns an error object with the value kCLErrorNetwork to the associated completion handler.) Here are some rules of thumb for using this class effectively:..."

So basically if you are testing and run your code more often than once a minute - the request gets bounced from the Apple server and you get the "fatal error: unexpectedly found nil while unwrapping an Optional value" error. Which if your like me, you assume is something to do with your code and spend hours changing bits and running the program repeatedly - making matters words ;o)


*unless you code is poling for the GPS coords every second (fine if thats what your app needs) but also asking the Apple server to convert this to a human readable location every second - thats the not fine bit.
Sean Crabtree
Sean Crabtree
1,793 Points

That page has been deleted, and can be found here as Weather Remix.

need2edit
PLUS
need2edit
Courses Plus Student 12,848 Points

For the life of me I can't get my App to prompt for location information. I've tried enabling location services in the Info.plist and have looked through Apple's documentation, but with no success. Anyone have any advice here, especially if there are any extra steps in the Xcode device capabilities or similar to enable Core Location.

Thanks!

Justin Dawkins
Justin Dawkins
9,080 Points

You need to add the property "NSLocationWhenInUseUsageDescription" (type string with an empty value) to your info.plist file.

If you open your info.plist file as source code and add the following code, you should see the prompt for access.

<key>NSLocationAlwaysUsageDescription</key>
<string></string>

From the documentation:

NSLocationWhenInUseUsageDescription (String - iOS) describes the reason why the app accesses the user’s location normally while running in the foreground. Include this key when your app uses location services to track the user’s current location directly. This key does not support using location services to monitor regions or monitor the user’s location using the significant location change service. The system includes the value of this key in the alert panel displayed to the user when requesting permission to use location services.

This key is required when you use the requestWhenInUseAuthorization method of the CLLocationManager class to request authorization for location services. If the key is not present when you call the requestWhenInUseAuthorization method without including this key, the system ignores your request.