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
Bradley Maskell
8,858 PointsStormy with user location and updated city location label.
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, UIAlertViewDelegate {
private let apiKey = "Your api key here"
// Location Manager
var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"
var locationManager: CLLocationManager!
var userLocation : String!
var userLatitude : Double!
var userLongitude : Double!
// Current Weather outlets
@IBOutlet weak var iconView: 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 refreshActivityIndicator: UIActivityIndicatorView!
@IBOutlet weak var cityNameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
refreshActivityIndicator.hidden = true
initLocationManager()
}
//Location Code
func initLocationManager() {
seenError = false
locationFixAchieved = false
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if ((error) != nil) {
if (seenError == false) {
seenError = true
print(error)
}
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if (locationFixAchieved == false) {
locationFixAchieved = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
var latitude = coord.latitude
var longitude = coord.longitude
//println(coord.latitude)
//println(coord.longitude)
self.userLatitude = coord.latitude
self.userLongitude = coord.longitude
//userLocation = "\(userLatitude),\(userLongitude)"
getCurrentWeatherData()
CLGeocoder().reverseGeocodeLocation(manager.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
self.displayLocationInfo(pm)
} else {
println("Problem with the data received from geocoder")
}
})
}
}
func displayLocationInfo(placemark: CLPlacemark?) {
if let containsPlacemark = placemark {
//stop updating location to save battery life
locationManager.stopUpdatingLocation()
let locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality : ""
let postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode : ""
let administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
let country = (containsPlacemark.country != nil) ? containsPlacemark.country : ""
println(locality)
println(postalCode)
println(administrativeArea)
println(country)
// cityNameLabel outlet
self.cityNameLabel.text = placemark?.locality
// println("locality is: \(placemark?.locality)")
// println("user location: \(userLocation)")
}
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch CLLocationManager.authorizationStatus() {
case .NotDetermined:
locationManager.requestAlwaysAuthorization()
case .Authorized:
locationManager.startUpdatingLocation()
case .AuthorizedWhenInUse, .Restricted, .Denied:
let alertController = UIAlertController(
title: "Background Location Access Disabled",
message: "In order to see local weather data, please open this app's settings and set location access to 'Always'.",
preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Settings", style: .Default) { (action) in
if let url = NSURL(string:UIApplicationOpenSettingsURLString) {
UIApplication.sharedApplication().openURL(url)
}
}
alertController.addAction(openAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
//Weather
func getCurrentWeatherData() -> Void {
userLocation = "\(userLatitude),\(userLongitude)"
let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
let forecastURL = NSURL(string: "\(userLocation)", 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)
//Test Connection and API with the following
println("Temp is: \(currentWeather.temperature)")
println("Time is: \(currentWeather.currentTime!)")
//println(weatherDictionary)
//Main dispatch
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.temperatureLabel.text = "\(currentWeather.temperature)"
self.iconView.image = currentWeather.icon!
self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
self.humidityLabel.text = "\(currentWeather.humidity)"
self.precipitationLabel.text = "\(currentWeather.precipProbability)"
self.summaryLabel.text = "\(currentWeather.summary)"
// Stop refresh animation
self.refreshActivityIndicator.stopAnimating()
self.refreshActivityIndicator.hidden = true
self.refreshButton.hidden = false
})
} else {
let networkIssueController = UIAlertController(title: "Error", message: "Unable to load data. Connectivity error!", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
networkIssueController.addAction(okButton)
let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
networkIssueController.addAction(cancelButton)
self.presentViewController(networkIssueController, animated: true, completion: nil)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// Stop refresh animation
self.refreshActivityIndicator.stopAnimating()
self.refreshActivityIndicator.hidden = true
self.refreshButton.hidden = false
})
}
})
downloadTask.resume()
}
@IBAction func refresh() {
initLocationManager()
refreshButton.hidden = true
refreshActivityIndicator.hidden = false
refreshActivityIndicator.startAnimating()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You must import any of these keys to your info.plist file. Open as source code and paste in which ever one you need.
<key>NSLocationAlwaysUsageDescription</key>
<string>We use you location to give you weather data</string>
<key>NSLocationUsageDescription</key>
<string>We use your location to give you weather data</string>
<key>NSLocationWhenInUsageDescription</key>
4 Answers
Bradley Maskell
8,858 PointsTo initialize, check for location authorization, and find coordinates for the api, and reverse geocoder to get your city name.
arnavthecoder
3,453 PointsWhich info.plist do i add it to. My app doesn't work and I did exactly what you did.
Nawfal Uchiwa
4,315 PointsThank's Bradley. But why do You have 3 location manager functions ?
K Jo
7,283 PointsBradley - I believe I have pasted your code exactly and pasted in the keys above to the info.plist. The build fails and I am getting the following error that I have never seen before.
error: couldn't parse contents of '/Users/..../Stormy/StormyTests/Info.plist': The data couldn’t be read because it isn’t in the correct format.
Any idea how to fix this?
Austin Murtha
4,843 PointsHow did you add the data to your plist file?
Bradley Maskell
8,858 PointsK Jo did you enter the entitlement keys in your StormyTest plist or your main app's plist?
Rune Rapley-Møller
Courses Plus Student 24,411 PointsRune Rapley-Møller
Courses Plus Student 24,411 PointsThanks Bradley Maskell :-) I commented out the :
because it didn't work with the refresh function. i placed it in the refresh function at the end and that works. Im not sure if that is correct, but i am learning b doing at the moment.