Search code examples
iosswiftcllocationmanagercllocationuserlocation

Swift 4 CLLocation User Location Longitude & Latitude


I converted to Swift 4. My tableview that pulls data from firebase and organizes it by distance from the users location has stopped working. The problem is my users location keeps on turning up nil. I've heard people having trouble with mapkit recently because of the conversion but unsure if this falls under the same category. So the line that says "let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)" returns nil. Thanks.

BreakPoint

override func viewDidLoad() {
    super.viewDidLoad()

    searchController.searchResultsUpdater = self
    searchController.dimsBackgroundDuringPresentation = false
    definesPresentationContext = true
    tableView.tableHeaderView = searchController.searchBar

    locationManager.delegate = self
    locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.startUpdatingLocation()
    locationManager.stopUpdatingLocation()
    locationManager.requestAlwaysAuthorization()

    getTableViewData()

    refresher = UIRefreshControl()
    refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
    refresher.addTarget(self, action: #selector(RegisteredLocations.handleRefresh(refreshControl:)), for: UIControlEvents.valueChanged)
    tableView.addSubview(refresher)
}

func getTableViewData() {
    Database.database().reference().child("Businesses").queryOrdered(byChild: "businessName").observe(.childAdded, with: { (snapshot) in

        let key = snapshot.key

        if(key == self.loggedInUser?.uid) {
            print("Same as logged in user, so don't show!")
        } else {
            if let locationValue = snapshot.value as? [String: AnyObject] {
                let lat = Double(locationValue["businessLatitude"] as! String)
                let long = Double(locationValue["businessLongitude"] as! String)
                let businessLocation = CLLocation(latitude: lat!, longitude: long!)

                let latitude = self.locationManager.location?.coordinate.latitude
                let longitude = self.locationManager.location?.coordinate.longitude
                let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)

                let distanceInMeters: Double = userLocation.distance(from: businessLocation)
                let distanceInMiles: Double = distanceInMeters * 0.00062137
                let distanceLabelText = String(format: "%.2f miles away", distanceInMiles)

                var singleChildDictionary = locationValue
                singleChildDictionary["distanceLabelText"] = distanceLabelText as AnyObject
                singleChildDictionary["distanceInMiles"] = distanceInMiles as AnyObject
                self.usersArray.append(singleChildDictionary as NSDictionary)
                self.usersArray = self.usersArray.sorted {
                    !($0?["distanceInMiles"] as! Double > $1?["distanceInMiles"] as! Double)
                }

            }
            //insert the rows
            //self.followUsersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
            self.followUsersTableView.reloadData()
        }

    }) { (error) in
        print(error.localizedDescription)
    }

}

Solution

  • You are calling locationManager.stopUpdatingLocation() immediately after you call locationManager.startUpdatingLocation().

    This won't work as you need to allow time for the location to be determined. You should not use location until you have received a call to the didUpdateLocations delegate method.

    If you are targeting iOS 9 and later and you only need a single location, then you should call requestLocation() rather than startUpdatingLocation() but you still need to wait for the callback to the delegate method.

    Once you have received a location, then you can load your table data.