fatal error: unexpectedly found nil while unwrapping an Optional value when getting Location? - ios

I am developing an app using swift I want to fetch current location of the user and want to show in google map so I wrote my code in my class I have included all the functions and methods (i.e) added and imported frameworks core location and also updated plist but I can't able to fetch current location rotationally some time I get the location but some time it crashed.
Here is the code what I am tried.
import CoreLocation
class HomeViewController: UIViewController, CLLocationManagerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.startUpdatingLocation()
let location: CLLocation? = locationManager.location
let coordinate: CLLocationCoordinate2D? = location?.coordinate ----> App crossed this line then it will crashed
print(coordinate!)
print(coordinate!.latitude)
print(coordinate!.longitude)
strForCurLatitude = "\(coordinate!.latitude)"
strForCurLongitude = "\(coordinate!.longitude)"}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
print("User allowed us to access location")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error while get location \(error)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locationManager.startUpdatingLocation()
let locationNew = locations.last
let coordinateNew: CLLocationCoordinate2D? = locationNew?.coordinate
strForCurLatitude = "\(coordinateNew!.latitude)"
strForCurLongitude = "\(coordinateNew!.longitude)"
strForLat=strForCurLatitude;
strForLong=strForCurLongitude;
print("User's Latitude is: \(Double(strForLat!)!)")
print("User's Longitude is: \(Double(strForLong!)!)")
self.locationManager.startUpdatingLocation()
}

Remove this from ViewDidLoad because you can not get location in viewDidLoad.
let location: CLLocation? = locationManager.location
let coordinate: CLLocationCoordinate2D? = location?.coordinate
print(coordinate!)
print(coordinate!.latitude)
print(coordinate!.longitude)
strForCurLatitude = "\(coordinate!.latitude)"
strForCurLongitude = "\(coordinate!.longitude)"
In CLLocationManager's following method best for getting location
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}

make a reference to CLLocationManager as variable, like this:
class HomeViewController {
var locationManager = CLLocationManager()
viewDidLoad() {
super.viewDidLoad()
}
// rest of code
}
in this case Location Manager should works properly.

Related

My Current Location Shows a Different Location, Google Maps - Xcode

I have implemented Google Maps but my Current Location is always USA. I am testing it on REAL device and i have location permissions added in info.plist. Google API key is also implemented in didFinishLaunchingWithOptions method of AppDelegate.
<key>NSLocationWhenInUseUsageDescription</key>
<string>By accessing your location, this app can help you navigate between different locations.</string>
Here is my code. I'm following this tutorial by raywenderlich.com. https://www.raywenderlich.com/7363101-google-maps-ios-sdk-tutorial-getting-started I have downloaded the material of this tutorial, used my API Key but still my current location is always USA. Tested on multiple real devices.
import UIKit
import GoogleMaps
import CoreLocation
class MapViewController: UIViewController {
#IBOutlet weak var mapView : GMSMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
if CLLocationManager.locationServicesEnabled() {
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.delegate = self
self.mapView.delegate = self
} else {
locationManager.requestWhenInUseAuthorization()
}
}
}
CLLocationManagerDelegate:-
extension MapViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
guard status == .authorizedWhenInUse else { return }
locationManager.startUpdatingLocation()
self.mapView.isMyLocationEnabled = true
self.mapView.settings.myLocationButton = true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else { return }
// the coordinates i get here are always from some city in USA.
mapView.camera = GMSCameraPosition(
target: location.coordinate,
zoom: 15,
bearing: 0,
viewingAngle: 0)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error: \(error)")
}
}
Please check the settings below as screenshot :

iOS - CLLocation Manager didUpdateLocations being called in one class but not another?

Hi I'm making a program that gets the users location and puts an according annotation on the map. I started by writing all of the code in the View Controller and it gets the location perfectly. Below is the working code in the view controller.
class MapViewController: UIViewController, CLLocationManagerDelegate {
var annotation = MKPointAnnotation()
var userLocation: CLLocation?
#IBOutlet weak var mapView: MKMapView!
var locationManager:CLLocationManager!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
determineCurrentLocation()
}
func determineCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
userLocation = locations[0] as CLLocation
print("user latitude = \(userLocation?.coordinate.latitude)")
print("user longitude = \(userLocation?.coordinate.longitude)")
annotation.coordinate = CLLocationCoordinate2D(latitude: (userLocation?.coordinate.latitude)!, longitude: (userLocation?.coordinate.longitude)!)
annotation.title = "You"
mapView.addAnnotation(annotation)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error \(error)")
}
However now when I try and recreate almost the exact same code in another swift file. didUpdateLocations never gets called. locationManager.startUpdatingLocation() does get called.
Below is my new swift file which I call from the View Controller. Is there any simple concept I'm missing here because I really don't see why this doesn't work.
import Foundation
import CoreLocation
class SendLocation: NSObject, CLLocationManagerDelegate {
var userLocation: CLLocation?
var locationManager:CLLocationManager!
func sendLocationPost() {
determineCurrentLocation()
}
func determineCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
print("WHY")
if CLLocationManager.locationServicesEnabled(){
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
userLocation = locations[0] as CLLocation
print("user latitude = \(userLocation?.coordinate.latitude)")
print("user longitude = \(userLocation?.coordinate.longitude)")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error \(error)")
}
}
I call it using :
let location = SendLocation()
location.sendLocationPost()`
in my View Controller
This happens because you are not keeping a reference to your SendLocation object.
Make SendLocation a property of your UIViewController.
For example, calling it from a static scope will not keep a reference.
WONT WORK:
static func sendLocation() {
let location = SendLocation()
location.sendLocationPost()
}
WILL WORK
let location = SendLocation()
func sendLocation() {
location.sendLocationPost()
}

Permission popup appear multiple time

I have a project in swift 2.When I launch the app first time there are three different type of permissions popup (Push notification, Location, Photo) that appear on the splash screen.I have add the Permission for location and photos in info.plist
The problem is when the app lunched the one(location) popup appear and disappear without any click then other(photos) popup appear and disappear after few seconds without any click.After few seconds the popup appear one by one and now the popup are display on the screen until I click any one option.
I want to display the permission popup only once when user tap on the button.I have searched about it but all the solutions that I found are in latest version of swift. Any suggestion regarding this is appreciated.
import CoreLocation
private var locationManager: CLLocationManager!
private var locationHandler: ((location: CLLocation?,error: NSError?) -> Void)?
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
func requestCurrentLocation(completionHandler:((location: CLLocation?,error: NSError?)->Void)!) {
locationHandler = completionHandler
if #available(iOS 9.0, *) {
locationManager.requestLocation()
} else {
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let locationHandler = locationHandler, let location = locations.first {
locationHandler(location: location, error: nil)
self.locationHandler = nil
locationManager.stopUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
if let locationHandler = locationHandler {
locationHandler(location: nil, error: error)
self.locationHandler = nil
}
}
The key is CLLocationManager always alive
import CoreLocation
class LocationManager: NSObject {
static let shared = LocationManager()
private lazy var locationManager: CLLocationManager = {
let manager = CLLocationManager()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
return manager
}()
private override init() {
super.init()
}
func askForPermission() {
locationManager.requestWhenInUseAuthorization()
}
func requestLocation() {
locationManager.requestLocation()
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// do something
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// do something
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// do something
}
}

Getting My Location with google maps swift

I've got this code:
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
and this code:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation = locations.last
print(userLocation)
let camera = GMSCameraPosition.cameraWithLatitude(userLocation!.coordinate.latitude,
longitude: userLocation!.coordinate.longitude, zoom: 12.5)
self.mapView.camera = camera
self.mapView.myLocationEnabled = true
// self.mapView.settings.myLocationButton = true
locationManager.stopUpdatingLocation()
}
This was working earlier but now it seems like locationManager isn't even being called as the print statement isn't returning any information at all. There are no errors in the code and I can't seem to figure out why the function isn't being called. Can anyone spot anything obvious that I'm missing?
Thank you
I just implemented this and I'm going to say you what I've done
First, you create a locationManager variable
let locationManager: CLLocationManager = CLLocationManager()
You have to request permission in the viewDidLoad()
viewMap.delegate = self
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
Then, I created an extension and I implemented the delegate
extension MyView: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
//here you configure the locationManager
locationManager.startUpdatingLocation()
viewMap.isMyLocationEnabled = true
viewMap.settings.myLocationButton = true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
}
I hope this help you, here works properly.

CLLocationCoordinates from locationManager didUpdateLocations

I am trying to use CoreLocation (once permission is granted) to get a user's CLLocationCoordinate2D, so that I can pass that information to an Uber deeplink (after a UIButton within my TableView is pressed).
I've figured out how to get the coordinates as CLLocations, and turn them into CLLocationCoordinates2D in the didUpdateLocations method, but can't seem to transfer them over to my buttonPressed function.
Can anyone explain how I can properly transfer the coordinates info to the uberButtonPressed method? I am also confused about how to get the locationManager to stop updating location once a suitable location is determined. Any help is much appreciated. By the way I am using this to instantiate Uber: https://github.com/kirby/uber
import UIKit
import CoreLocation
import MapKit
class ATableViewController: UITableViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var location: CLLocation?
var coordinate: CLLocationCoordinate2D?
// Implemented tableView methods etc here...
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let newLocation = locations.last as! CLLocation
println("DID UPDATE LOCATIONS \(newLocation)")
location = newLocation
coordinate = location!.coordinate
println("WE HAVE THE COORDINATES \(coordinate!.latitude) and \(coordinate!.longitude)") // this prints along with DID UPDATE LOCATIONS
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("error:" + error.localizedDescription)
}
func uberButtonPressed(sender: UIButton!) {
let senderButton = sender
println(senderButton.tag)
let authStatus: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
if authStatus == .NotDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
var pickupLocation = coordinate! // fatal error: unexpectedly found nil while unwrapping an Optional value
println(pickupLocation)
// // Create an Uber instance
// var uber = Uber(pickupLocation: pickupLocation)
//
// Set a few optional properties
// uber.pickupNickname = "OK"
//
// uber.dropoffLocation = CLLocationCoordinate2D(latitude: 47.591351, longitude: -122.332271)
// uber.dropoffNickname = "whatever"
//
// // Let's do it!
// uber.deepLink()
//
}
You should move var pickupLocation = coordinate! into your didUpdateLocations. Once assigned, you can call locationManager.stopUpdatingLocation() also from inside 'didUpdateLocation or your value for coordinate with keep updating. After stopping the locationManager, call a NEW function to run the rest of your code currently in func uberButtonPressed
I had the same problem.
Instead of calling the delegate method like this:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
debugPrint("NOT CALLED-- didUpdateLocations AnyObject")
}
I changed into:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
debugPrint("CALLED-- didUpdateLocations CLLocation")
}
The problem is that you are unwrapping coordinate which is a CLLocationCoordinate2D? with a !. Since coordinate is from location which is a CLLocation?. It is possible that coordinate is nil and location is nil, especially before location services have had a chance to kick in. Only run the rest of uberButtonPressed: for the case where coordinate and location are not nil by using if let currentCoordinate = coordinate?, and in that case, call locationManager.stopUpdatingLocation().

Resources