MapView Not Showing Location - ios

I'm currently developing an iOS app, and one of its functions include locating places of interest for nightlife. However, when my MapView loads, current user location is not displayed, even though location access has been granted.
Here is my code:
import UIKit
import MapKit
import CoreLocation
class BarMapVC: UIViewController {
#IBOutlet weak var searchBtn: UIBarButtonItem!
#IBOutlet weak var doneBtn: UIBarButtonItem!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var locationBtn: UIButton!
#IBOutlet weak var barMapView: MKMapView!
var locationManager = CLLocationManager()
let authorizationStatus = CLLocationManager.authorizationStatus()
let regionRadius: Double = 1000
override func viewDidLoad() {
super.viewDidLoad()
searchBar.isHidden = true
barMapView.delegate = self
locationManager.delegate = self
configureLocationServices()
centerMapOnUserLocation()
}
#IBAction func searchBtnWasPressed(_ sender: Any) {
searchBar.isHidden = false
}
#IBAction func doneBtnWasPressed(_ sender: Any) {
dismiss(animated: true)
}
#IBAction func locationBtnWasPressed(_ sender: Any) {
if authorizationStatus == .authorizedAlways || authorizationStatus == .authorizedWhenInUse {
centerMapOnUserLocation()
}
}
}
extension BarMapVC: MKMapViewDelegate {
func centerMapOnUserLocation() {
guard let coordinate = locationManager.location?.coordinate else { return }
let coordinateRegion = MKCoordinateRegionMakeWithDistance(coordinate, regionRadius * 2.0, regionRadius * 2.0)
barMapView.setRegion(coordinateRegion, animated: true)
}
}
extension BarMapVC: CLLocationManagerDelegate {
func configureLocationServices() {
if authorizationStatus == .notDetermined {
locationManager.requestAlwaysAuthorization()
} else {
return
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
centerMapOnUserLocation()
}
}
I'm using CLLocation Manager, complying to mapViewDelegate, as well as have all needed outlets. Anything I' m doing wrong?

You can set this on your map view:
barMapView.showsUserLocation = true

Related

UI won't update after getting json data from Openweathermap IOS 4 Xcode 10

my JSON have been printed to console with the correct value request. but label.text and city.text won't update UI in main controller
#IBOutlet weak var icon: UIImageView!
#IBOutlet weak var date: UILabel!
#IBOutlet weak var weatherType: UILabel!
#IBOutlet weak var degree: UILabel!
#IBOutlet weak var city: UILabel!
var currentWeather : CurrentWeather!
override func viewDidLoad() {
super.viewDidLoad()
currentWeather = CurrentWeather()
}
override func viewDidAppear(_ animated: Bool) {
super .viewDidAppear(animated)
locationAuthStatus()
}
func locationAuthStatus() {
if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
currentLocaion = locationManager.location
//Location.sharedIntance.latitude = currentLocaion.coordinate.latitude
//Location.sharedIntance.longitude = currentLocaion.coordinate.longitude
print(currentLocaion)
currentWeather.downloadWeatherDetail {
downloadForecastData {
self.updateMainUI()
}
}
} else {
locationManager.requestWhenInUseAuthorization()
locationAuthStatus()
}
}
func updateMainUI() {
icon.image = UIImage(named: currentWeather.weatherType)
city.text = currentWeather.cityName
degree.text = "\(currentWeather.currentTemp)"
weatherType.text = currentWeather.weatherType
date.text = currentWeather.date
}
}
I am new to coding and 'm having a hard figuring out why isn't it showing since I confirmed that I am pulling data from Json to my console
These lines won't do what you expect.
locationManager.requestWhenInUseAuthorization()
locationAuthStatus()
Your call to requestWhenInUseAuthorization is asynchronous and should be handled by a CLLocationManagerDelegate which can be your view controller. You can do this like this:
class ViewController: UITableViewController, CLLocationManagerDelegate {
// rest of class
Add these functions to your class
func locationManager(_ manager: CLLocationManager, didUpdateLocations objects: [CLLocation]) {
let location = objects[objects.count-1]
let currentLocation = location
print(currentLocation)
currentWeather.downloadWeatherDetail {
downloadForecastData {
self.updateMainUI()
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// handle error
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
locationManager.startUpdatingLocation()
}

Swift 4 CoreLocation not working

why this code does not working? I guess it's something with didUpdateLocations overrated method? How I can correctly connect them with my labels and make them a live :)
import UIKit
import CoreLocation
class MainVC: UIViewController, CLLocationManagerDelegate {
var walking = false
var pause = false
var locationManager: CLLocationManager = CLLocationManager()
var startLocation: CLLocation!
var speed: CLLocationSpeed = CLLocationSpeed()
#IBOutlet weak var latitudeLabel: UILabel!
#IBOutlet weak var longitudeLabel: UILabel!
#IBOutlet weak var horizontalAccuracyLabel: UILabel!
#IBOutlet weak var verticalAccuracyLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
#IBOutlet weak var altitudeLabel: UILabel!
#IBOutlet weak var speedLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
startLocation = nil
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func startDistance(_ sender: UIButton) {
startLocation = nil
walking = true
}
#IBAction func stopDistance(_ sender: UIButton) {
walking = false
}
#IBAction func resetDistance(_ sender: UIButton) {
startLocation = nil
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let latestLocation: AnyObject = locations[locations.count - 1]
latitudeLabel.text = String(format: "%.4f",latestLocation.coordinate.latitude)
longitudeLabel.text = String(format: "%.4f",latestLocation.coordinate.longitude)
horizontalAccuracyLabel.text = String(format: "%.4f",latestLocation.horizontalAccuracy)
verticalAccuracyLabel.text = String(format: "%.4f",latestLocation.verticalAccuracy)
altitudeLabel.text = String(format: "%.4f",latestLocation.altitude)
if walking == true {
if startLocation == nil {
startLocation = latestLocation as! CLLocation
speed = locationManager.location!.speed
speedLabel.text = String(format: "%.0f km/h", speed * 3.6)
}
let distanceBetween: CLLocationDistance =
latestLocation.distance(from: startLocation)
distanceLabel.text = String(format: "%.2f", distanceBetween)
}
}
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)
{
// capLabel.text = String(format: "%.4f",newHeading.magneticHeading)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
}
I also added: Location Always Usage Description in my info.plist
And i allowed Location in the Settings on my simulator too.
Thank you.
To configure always authorization in Swift 4 for location services which I can see you have written in your code self.locationManager.requestAlwaysAuthorization(), do the following:
There is a new key NSLocationAlwaysAndWhenInUsageDescription which is also required in your info.plist
<key>NSLocationAlwaysUsageDescription</key>
<string> location permission text.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string> location permission text.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string> location permission text.</string>
Take a look in the documentation here
You are required to include the NSLocationWhenInUseUsageDescription
and NSLocationAlwaysAndWhenInUsageDescription keys in your app's
Info.plist file. (If your app supports iOS 10 and earlier, the
NSLocationAlwaysUsageDescription key is also required.) If those keys
are not present, authorization requests fail immediately.
So we will have a single prompt now.

location authorization alert showing up after app closes

I created a singleton class to handle location authorization because I needed it for several views in my app. So I created the below Location.swift class.
NOTE: I have added correctly into Info.plist, and have looked at several other posts but none seem to address this (at least none I found)
protocol LocationServiceDelegate {
func tracingLocation(currentLocation: CLLocation)
func tracingLocationDidFailWithError(error: NSError)
}
class Location: NSObject,CLLocationManagerDelegate {
var latitude: Double!
var longitude: Double!
var currentLocation : CLLocation!
var locationManager: CLLocationManager?
var lastLocation: CLLocation?
var delegate: LocationServiceDelegate?
static let sharedInstance:Location = {
let instance = Location()
return instance
}()
override init() {
super.init()
self.locationManager = CLLocationManager()
self.locationManager?.delegate = self
guard let locationManagers = self.locationManager else {
return
}
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManagers.requestWhenInUseAuthorization()
}
locationManagers.desiredAccuracy = kCLLocationAccuracyBest
locationManagers.pausesLocationUpdatesAutomatically = false
locationManagers.distanceFilter = 0.1
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
self.lastLocation = location
updateLocation(currentLocation: location)
}
#nonobjc func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
locationManager?.requestWhenInUseAuthorization()
break
case .authorizedWhenInUse:
locationManager?.startUpdatingLocation()
break
case .authorizedAlways:
locationManager?.startUpdatingLocation()
break
case .restricted:
// restricted by e.g. parental controls. User can't enable Location Services
break
case .denied:
// user denied your app access to Location Services, but can grant access from Settings.app
break
}
}
// Private function
private func updateLocation(currentLocation: CLLocation){
guard let delegate = self.delegate else {
return
}
delegate.tracingLocation(currentLocation: currentLocation)
}
private func updateLocationDidFailWithError(error: NSError) {
guard let delegate = self.delegate else {
return
}
delegate.tracingLocationDidFailWithError(error: error)
}
func startUpdatingLocation() {
print("Starting Location Updates")
self.locationManager?.startUpdatingLocation()
currentLocation = locationManager?.location
Location.sharedInstance.latitude = currentLocation.coordinate.latitude
Location.sharedInstance.longitude = currentLocation.coordinate.longitude
print(Location.sharedInstance.latitude, Location.sharedInstance.longitude)
// self.locationManager?.startMonitoringSignificantLocationChanges()
}
func stopUpdatingLocation() {
print("Stop Location Updates")
self.locationManager?.stopUpdatingLocation()
}
}
My app is crashing, and I think its because the location authorization is not set in the beginning. The funny thing is that the request alert which prompts the user to allow location services doesn't show up until you leave the app.
Once you close the app and accept the location services, the app works fine. So my question is, why isn't the alert showing up?
it is also interesting to note that this is only occurring through an actual device. In the simulator the alert pops up as expected when the initial view is loading.
my first view that is supposed to load and show data is as follows:
import UIKit
import Alamofire
class CurrentWeatherVC: UIViewController {
#IBOutlet weak var locationLabel: UILabel!
#IBOutlet weak var weatherIcon: UIImageView!
#IBOutlet weak var currentTempLabel: UILabel!
#IBOutlet weak var weatherTypeLabel: UILabel!
var currentWeather : CurrentWeather!
override func viewDidLoad() {
super.viewDidLoad()
Location.sharedInstance.locationManager(manager: Location.sharedInstance.locationManager, didChangeAuthorizationStatus: .authorizedWhenInUse)
currentWeather = CurrentWeather()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Location.sharedInstance.startUpdatingLocation()
currentWeather.downloadWeatherDetails {
self.updateMainUI()
}
}
func updateMainUI() {
//Double value convterted to string for current temp.
//Added the degree symbol here
//For forecast it gets added in before saved into list so be aware of that.
currentTempLabel.text = "\(currentWeather.currentTemp)°"
weatherTypeLabel.text = currentWeather.weatherType
locationLabel.text = currentWeather.cityName
weatherIcon.image = UIImage(named: currentWeather.weatherType)
}
}
I suspect downloadWeatherDetailss implementation uses a dataTask or one of the other NSURLSession methods that run in background.
Make sure to call UI stuff only on the mainQueue:
// ...
DispatchQueue.main.async {
self.updateMainUI()
}
// ...

Making an app using swift that gets user's location

I ran my code for getting the user's location and this is the error I get. Can someone please help me figure it out?
My code is as follows:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var citybtn: UIButton!
#IBOutlet weak var citylbl: UILabel!
let locationManager = CLLocationManager()
var currentLocation : CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Used to start getting the users location
//let locationManager = CLLocationManager()
// For use when the app is open
//locationManager.requestAlwaysAuthorization()
// If location services is enabled get the users location
//if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest // You can change the locaiton accuary here.
locationManager.requestWhenInUseAuthorization()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
locationAuthStatus()
}
func locationAuthStatus() {
if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
currentLocation = locationManager.location
print(currentLocation.coordinate.latitude)
print(currentLocation.coordinate.longitude)
} else {
locationManager.requestWhenInUseAuthorization()
locationAuthStatus()
}
}
#IBAction func buttonpresses(_ sender: Any) {
}
}
sounds like you did not enable the location update capability of your target:
choose target
select capabilities
in Background Modes, tick Location updates

Swift Closure, Missing argument for parameter #1 in call

Hello all who want to help. I am trying to do a callback function when I get my location updated. But I run into a problem that I have no idea how to solve.
class ViewController: UIViewController {
#IBOutlet weak var currentTemperatureLabel: UILabel?
#IBOutlet weak var currentHumidityLabel: UILabel?
#IBOutlet weak var currentPrecipitationLabel: UILabel?
#IBOutlet weak var currentWeatherIcon: UIImageView?
#IBOutlet weak var currentWeatherSummary: UILabel?
private let APIKey = "someString"
let location = LocationService(){
callBackFunction in
loadData()
}
func loadData()
{
let forecastService = ForecastService(APIKey: APIKey)
forecastService.getForecast(location.latitude, long: location.longitude)
{
(let currentW) in
if let currentWeather = currentW
{
dispatch_async(dispatch_get_main_queue())
{
if tjekIfNil(currentWeather.temperature)
{
self.currentTemperatureLabel?.text = "\(currentWeather.temperature!)°"
}
if tjekIfNil(currentWeather.humidity)
{
self.currentHumidityLabel?.text = "\(currentWeather.humidity!)%"
}
if tjekIfNil(currentWeather.precipProbability)
{
self.currentPrecipitationLabel?.text = "\(currentWeather.precipProbability!)%"
}
if tjekIfNil(currentWeather.icon)
{
self.currentWeatherIcon?.image = currentWeather.icon
}
if tjekIfNil(currentWeather.summary)
{
self.currentWeatherSummary?.text = currentWeather.summary
}
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
location.requestPermission()
location.getLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The error occurs here when I call loadData()
let location = LocationService(){
callBackFunction in
println("data is loading")
loadData()
}
Here is the LocationService class
import CoreLocation
class LocationService: NSObject, CLLocationManagerDelegate
{
var locationManager : CLLocationManager!
var location : CLLocation?
var longitude : Double?
var latitude : Double?
let callBackFunction : ()->()
init(callBackFunc: (Void->Void))
{
locationManager = CLLocationManager()
callBackFunction = callBackFunc
}
func requestPermission()
{
locationManager.requestWhenInUseAuthorization()
}
func getLocation()
{
if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse)
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}else
{
location = nil
longitude = nil
latitude = nil
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
location = locationManager.location
if tjekIfNil(location?.coordinate.longitude)
{longitude = location!.coordinate.longitude}
if tjekIfNil(location?.coordinate.latitude)
{latitude = location!.coordinate.latitude}
locationManager.stopUpdatingLocation()
println(longitude)
println(latitude)
callBackFunction()
}
}
From what I have found myself it is something about calling loadData() as a class function while it is a instance function.
Im still very new to swift so I don't really know how to solve the problem, so any help would be greatly appreciated.
Edit:
I found the solotion. The reason that the error was popping op was because the function loadData() was initilaized but the callBackFunction wasn't properly initilaized. I solved it by moving the callBackFunction to getLocation() instead of the initialization.
The issue is with the way you are passing the callback, instead of:
let location = LocationService(){
callBackFunction in
loadData()
}
You need to pass the callback like:
let location = LocationService(callBackFunc:loadData)

Resources