Reputation: 57
Coordinates return nil, I have entered requestAlwaysAuthorization and requestWhenInUseAuthorization in the plist file, but yet nothing happens. Here is my code.
what is going in this code? I can't find where the error is. It's just returning nil for cordinates
import UIKit
import CoreLocation
class ViewController: UIViewController,CLLocationManagerDelegate {
//Location
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 "Display Objects"
@IBOutlet weak var userLocationLabel: UILabel!
@IBOutlet weak var visibilityLabel: UILabel!
@IBOutlet weak var temperatureLabel: UILabel!
@IBOutlet weak var iconView: UIImageView!
@IBOutlet weak var currentTimeLabel: UILabel!
@IBOutlet weak var humidityLabel: UILabel!
@IBOutlet weak var precipitationLabel: UILabel!
@IBOutlet weak var summaryLabel: UILabel!
@IBOutlet weak var windSpeedLabel: UILabel!
@IBOutlet weak var refreshButton: UIButton!
@IBOutlet weak var refreshActivityIndicator: UIActivityIndicatorView!
//API KEY
private let apiKey = "09ca8e3e75fafbadaf4b8594dabe860e"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
refreshActivityIndicator.hidden = true
getCurrentWeatherData()
}
//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]!) {
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
let pm = placemarks[0] as! CLPlacemark
self.displayLocationInfo(pm)
})
if (locationFixAchieved == false) {
locationFixAchieved = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as! CLLocation
var coord = locationObj.coordinate
self.userLatitude = coord.latitude
self.userLongitude = coord.longitude
getCurrentWeatherData()
}
}
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)
self.userLocationLabel.text = "\(locality), \(administrativeArea)"
}
}
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
func getCurrentWeatherData() -> Void {
userLocation = "\(userLatitude),\(userLongitude)"
// DC cord. = "44.029002,-92.855343"
//URL
let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
let forecastURL = NSURL(string:"\(userLocation)", relativeToURL: baseURL)
// creates data object; to get and save data from online
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL!, completionHandler: { (location:NSURL!, response:NSURLResponse!, error: NSError!) -> Void in
// if everything goes alright (no errors then run code)
if (error == nil) {
//turn JSON dictionary to NSDictionary so it's easier to work with
let dataObject = NSData(contentsOfURL: location)
let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as! NSDictionary
//bring weather dictionary from the CurrentWeather file
let currentWeather = Current(weatherDictionary: weatherDictionary)
println(weatherDictionary)
//update view with current weather information
dispatch_sync(dispatch_get_main_queue(), { () -> Void in
self.temperatureLabel.text = "\(currentWeather.temperature)"
self.iconView.image = currentWeather.icon!
self.currentTimeLabel.text = "\(currentWeather.currentTime!)"
self.humidityLabel.text = "\(currentWeather.humidity * 100)%"
self.precipitationLabel.text = "\(currentWeather.precipProbability * 100)%"
self.summaryLabel.text = "\(currentWeather.summary)"
self.windSpeedLabel.text = "\(currentWeather.windSpeed) MPH"
self.visibilityLabel.text = "\(currentWeather.visibility) Mi"
//stop refresh animation
self.refreshActivityIndicator.stopAnimating()
self.refreshActivityIndicator.hidden = true
self.refreshButton.hidden = false
})
}
else {
let networkIssueController = UIAlertController(title: "Error", message: "Network Connectivity Error! Can't load data", preferredStyle: .Alert)
println(error)
//information for ok button in alertView
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
networkIssueController.addAction(okButton)
//information for cancel button in alertView
let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
networkIssueController.addAction(cancelButton)
//if an error occurs show alert
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()
}
//refresh method
@IBAction func refresh() {
getCurrentWeatherData()
refreshButton.hidden = true
refreshActivityIndicator.hidden = false
refreshActivityIndicator.startAnimating()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Upvotes: 0
Views: 2245
Reputation: 7168
I struggled with this step as well. And MirekE has pointed out all great points. I have built on what MirekE stated and showed yo some code to maybe help explain it in more detail.
Step 1) Make sure your info.plist have the following.Do not forget to give them a value like - Need to use your location to get the weather for your current location. Or some thing along those lines.
NSLocationAlwaysUsageDescription
Privacy - Location Usage Description
NSLocationWhenInUseUsageDescription
Step 2) I added this code to my project and combined with step 1 then I would get the alert views to allow location services.
//this is part of my viewDidLoad()
if ( ios8() ) {
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
/*
iOS 8 Utility
*/
func ios8() -> Bool {
if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {
return false
} else {
return true
}
}
Step 3) I used defaults to store them for another purpose.
// MARK: CLLocationManagerDelegate
public func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var location:CLLocation = locations[locations.count-1]as! CLLocation
if (location.horizontalAccuracy > 0) {
self.locationManager.stopUpdatingLocation()
self.defaults.setDouble(location.coordinate.latitude, forKey: "lat")
self.defaults.setDouble(location.coordinate.longitude, forKey: "lon")
println("lat \(location.coordinate.latitude) lon \(location.coordinate.longitude)")
defaults.synchronize()
updateLocationInfo() // This is where you would call your getCurrentWeatherData()
}
}
// MARK: locationManager
public func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println(error)
self.loading.text = "Can't get your location!"
}
Upvotes: 1
Reputation: 11555
Perhaps you already handled all these situations in code that is not shown, but here is a list of things that I think are missing in your code:
initLocationManager
in your code.getCurrentWeatherData()
in your viewDidLoad()
won't work, you need to call it from locationManager(didUpdateLocations)
.requestAlwaysAuthorization
or requestWhenInUseAuthorization
alone to the application options is not enough. You also need to provide NSLocationAlwaysUsageDescription
with text explaining why you need access.locationManager(didUpdateLocations)
to see if it gets called at all.Upvotes: 2