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 locationManager Swift help.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate, UIAlertViewDelegate {
let manager = CLLocationManager()
var seenError : Bool = false
var locationFixAchieved : Bool = false
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!
//Daily Weather outlets
private let apiKey = "PRIVATE"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
refreshActivityIndicator.hidden = true
triggerLocationServices()
}
//Location Code
func triggerLocationServices() {
if CLLocationManager.locationServicesEnabled() {
if self.manager.respondsToSelector("requestAlwaysAuthorization") {
manager.requestAlwaysAuthorization()
} else {
startUpdatingLocation()
}
}
}
func startUpdatingLocation() {
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
manager.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
println(coord.latitude)
println(coord.longitude)
self.userLatitude = coord.latitude
self.userLongitude = coord.longitude
println(userLocation)
getCurrentWeatherData()
}
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch CLLocationManager.authorizationStatus() {
case .NotDetermined:
manager.requestAlwaysAuthorization()
case .Authorized:
manager.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(currentWeather.temperature)
println(currentWeather.currentTime!)
println(weatherDictionary)
//Main dispatch AKA Party Time!
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() {
refreshButton.hidden = true
refreshActivityIndicator.hidden = false
refreshActivityIndicator.startAnimating()
getCurrentWeatherData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Everything compiles with no warnings. But when I run the app on the phone or simulator it doesn't ask for permission to track location services, and when you go into Settings and change the apps location permission to always it doesn't remember it when you go back to the app. I've looked everywhere online and I just can't seem to find the answer. I'm sure it's right under my nose and I just don't see it so I'm hoping someone here can help.
5 Answers
Pasan Premaratne
Treehouse TeacherHave you set the relevant keys in the Info.plist? This is a tricky/annoying thing in iOS 8 because its not highlighted properly in the docs and not including the keys causes the app to fail silently without any errors, as you're experiencing. Depending on which kind of permission you're requesting, you need to go to your Info.plist and add either NSLocationAlwaysUsageDescription or
NSLocationWhenInUseUsageDescription (with a value of YES) to your list.
Let me know if that works.
Eric Whittaker
2,974 PointsI don't understand how there are 3 "func locationManager" methods called. Should'nt there only be one?
Pasan Premaratne
Treehouse TeacherThe CLLocationManagerDelegate protocol has a bunch of different methods that you can implement for location related updates. The three methods being used here (1) check for the location authorization status, (2) inform the delegate when location updates have been received and (3) inform the delegate when location fails
Rune Rapley-Møller
Courses Plus Student 24,411 PointsI would like to update the city name label when the location gets updated in the Stormy app.
I have tried to have a look in the docs and the forum but all i could find is this func:
func reverseGeocodeLocation(location: CLLocation!, completionHandler: CLGeocodeCompletionHandler!){
}
So what i understand is that i need to input the geo coordinates and the output will then be a string with the city name etc.
I'm very new to iOS development and Swift so a little help to point me in the right direction would be greatly appreciated.
Bradley Maskell Pasan Premaratne
thanks in advance
arnavthecoder
3,453 PointsSomething cool I learned is you can import iAd kit and write the following code in the view did load method:
self.canDisplayBannerAds = true
arnavthecoder
3,453 PointsThen you need to download the ad workbench
Joshua Rystedt
4,086 PointsI have been wrestling with Core Location for over a week. I have tried numerous implementations to no avail. My most recent attempt was to adapt the code in this thread. However, although manager.startUpdatingLocation() inside viewDidLoad is executed none of my CLLocationManager methods (placed in the ViewController class but outside of viewDidLoad) will execute (I have been using breakpoints to determine this). My app does compile and run without errors.
I think my issue lies either in that I am only testing this in the iOS simulator or in that I am attempting to build with Swift 2 in XCode 7.
Do Core Location tests need to take place on an iOS device or is the simulator sufficient?
Anyone try updating their Core Location implementations to Swift 2?
I am absolutely stumped.
Bradley Maskell
8,858 PointsBradley Maskell
8,858 PointsPasan Premaratne
Gotcha. I just did that and found an error around
let currentWeather = Current(weatherDictionary: weatherDictionary). I'm not really sure what i'm doing wrong here since the app is pretty much untouched from the video other than adding CLLocation.
Bradley Maskell
8,858 PointsBradley Maskell
8,858 PointsI figured it out. Thanks Pasan Premaratne