I've worked with CLLocationManager a lot before and I have several other projects where this works just fine with the EXACT SAME code... the necessary properties are in the info.Plist as well.
I've tried this both on the simulator and device, both which worked fine in my other projects. If anyone is able to help that would be great because I'm about to lose my mind. Thank you!
Required plist properties
<key>NSLocationAlwaysUsageDescription </key>
<string>Can we use your location? </string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location?</string>
The code in the main VC
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let clientKey = ""
let clientSecred = ""
let pushSecret = ""
let fourSquareVersion = ""
let section = ""
var latLong = ""
var currentLat : Double?
var currentLong : Double?
var locationManager : CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
if let currentLocation : CLLocation = newLocation {
currentLat = currentLocation.coordinate.latitude
currentLong = currentLocation.coordinate.longitude
print(currentLat)
print(currentLong)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
So it turns out that there was a space after NSLocationAlwaysUsageDescription in the info.plist.
Related
I am trying to get the splash view ( back_button ) to remove itself once the webpage fully loads, I had done quite a bit of researching and they always point to the same code as an answer. However, mine will not get called. Can somebody advise what I am doing wrong?
import UIKit
import WebKit
class ViewController: UIViewController {
#IBOutlet weak var LoadingView: UIImageView!
var webView: WKWebView?
var bgImage: UIImageView?
var imageViewObject :UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
//var imageViewObject :UIImageView
let screenSize: CGRect = UIScreen.main.bounds
imageViewObject = UIImageView(frame:CGRect(x:0,y: 0, width: screenSize.width, height: screenSize.height))
imageViewObject?.image = UIImage(named:"back_image")
webView?.navigationDelegate = self as? WKNavigationDelegate
self.view.addSubview(imageViewObject!)
let myURL = URL(string: "https://www.google.com")
let myRequest = URLRequest(url: myURL!)
_ = webView?.load(myRequest)
}
override func loadView() {
super.loadView()
//self.view.sendSubview(toBack: imageViewObject)
//self.view = self.LoadingView
self.webView = WKWebView()
self.view = self.webView
}
#IBAction func BackButton(_ sender: Any) {
if(webView?.canGoBack)!
{
webView?.goBack();
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("TEST")
imageViewObject?.removeFromSuperview()
}
func webViewDidFinishLoad(webView: WKWebView) {
imageViewObject?.removeFromSuperview()
self.view = self.webView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
you have to conform to it's protocol delegate by putting this line of code in viewDidLoad
webView?.uiDelegate = self
after doing that , now if you want to use delegation method's you have to put your viewController as a subclass of UIWebViewDelegate
class ViewController: UIViewController ,UIWebViewDelegate{
I fixed this by making
webView?.navigationDelegate = self
and adding this to the Class
class ViewController: UIViewController, WKNavigationDelegate
The following is a code snippet from the ViewController.swift file inside my Swift 3 project. What should I change to make it work or could you give any pointers? Do you know why it is not working and instead, going to some arbritrary location instead of my location after the notification for the current location is done?
import Cocoa
import MapKit
import CoreLocation
class ViewController: NSViewController, CLLocationManagerDelegate , MKMapViewDelegate{
#IBOutlet weak var STAVO_map: MKMapView!
var manager: CLLocationManager!
var currentLocation : CLLocation!
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
STAVO_map.delegate = self
STAVO_map.showsUserLocation = true
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
if CLLocationManager.locationServicesEnabled() {
manager.startUpdatingLocation()
}
DispatchQueue.main.async {
self.manager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last as! CLLocation
self.manager.stopUpdatingLocation()
let region = MKCoordinateRegionMakeWithDistance(location.coordinate, 500, 500)
self.STAVO_map.setRegion(region, animated: true)
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
A few things things, first I would change didUpdateLocations to
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last as! CLLocation
manager.stopUpdatingLocation()
let region = MKCoordinateRegionMakeWithDistance(location.coordinate, 1000, 1000)
self.STAVO_map.setRegion(region, animated: true)
}
In viewDidLoad…startUpdatingLocation is an async function so you’re always going to get noLocation set until didUpdateLocations is called. I would remove the 3 lines where you set noLocation, the viewRegion and setRegion. You shouldn’t need to call startUpdatingLocation twice so you can remove the second call (besides, viewDidLoad runs in main queue by default so no need for DispatchQueue)
I have an app that has two ViewControllers. On the first there is a count of current speed in realtime through CLLocationManager. Also there is a label that shows current speed with update by timer (NSTimer). In second ViewController there is another Label, where this current speed has to be shown too. It shows it, but don't update. I tried to set second timer (different ways: in first VC, in second VC - there is always was an error or just nothing).
Will be grateful for help, thanks!
First VC
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var currentSpeedLabel: UILabel!
var manager = CLLocationManager()
var currentSpeed: CLLocationSpeed = CLLocationSpeed()
var timer = NSTimer()
override func viewDidLoad() {
super.viewDidLoad()
mapView.mapType = MKMapType.Hybrid
trackingMe()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func HUDMapView(sender: AnyObject) {
speedCount()
}
#IBAction func findMe(sender: AnyObject) {
trackingMe()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation: CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
let location = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
mapView.setRegion(region, animated: true)
}
func trackingMe() {
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
mapView.showsUserLocation = true
currentSpeedUpdate()
}
func currentSpeedUpdate() {
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("speedCount"), userInfo: nil, repeats: true)
}
func speedCount() {
currentSpeed = manager.location!.speed
currentSpeedLabel.text = String(format: "%.0f km/h", currentSpeed * 3.6)
}
override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!) {
let speedController = segue.destinationViewController as! speedViewController
currentSpeed = manager.location!.speed
speedController.showSpeed = currentSpeedLabel.text
}
}
Second VC
import UIKit
class speedViewController: UIViewController {
#IBOutlet weak var secondSpeedLabel: UILabel!
var showSpeed: String!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
secondSpeedLabel.text = showSpeed
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func back(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Project Link
You could use a Singleton to hold the LocationManager. Then you can access it from all over your app. When you move to a second VC you can either change the delegate to the second VC or just get the needed data manually.
Remember that a delegate can only point to one "receiver". Changing the delegate will stop updates in the first VC. but since it is now a Singleton you can also store information in there about past locations / speeds. When dismissing the second VC get the stored data and update.
This will keep running until you call stop()
The code was simplified a bit to illustrate the idea.
VC Code:
import UIKit
import CoreLocation
class ViewController: UIViewController, TrackerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
Tracker.shared.delegate = self
Tracker.shared.start()
}
func speedUpdate(speed: CLLocationSpeed) {
print(speed)
}
}
Singleton Code:
import UIKit
import MapKit
import CoreLocation
class Tracker: NSObject, CLLocationManagerDelegate {
static var shared = Tracker()
private var manager = CLLocationManager()
private var timer = NSTimer()
var region : MKCoordinateRegion?
var currentSpeed: CLLocationSpeed = CLLocationSpeed()
weak var delegate : TrackerDelegate?
private override init() {
super.init()
manager.delegate = self
manager.requestWhenInUseAuthorization()
}
internal func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
let userLocation: CLLocation = locations[0] as CLLocation
let coordinates2D = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.05, 0.05)
region = MKCoordinateRegion(center: coordinates2D, span: span)
currentSpeed = userLocation.speed
guard let del = delegate else {
return
}
del.speedUpdate(currentSpeed)
}
func start() {
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("loopUpdate"), userInfo: nil, repeats: true)
}
func stop() {
timer.invalidate()
}
internal func loopUpdate() {
// restart updating
manager.startUpdatingLocation()
}
}
Delegate for the Singleton:
Add more functions, or more values to the current function to get more feedback.
protocol TrackerDelegate : class {
func speedUpdate(speed:CLLocationSpeed)
}
I recently updated to xCode 7 which uses iOS 9 and when I run the following app, the location is supposed to print to the console but that's not happening.
The app will build successfully, the map displays, but the location data doesn't print. Even if the move the map, it still doesn't print.
The code should be correct, i've imported all of the necessary frameworks and set both the NSLocationWhenInUseUsageDescription & NSLocationAlwaysUsageDescription in the Info.plist file along w/ their values.
Below is the code:
// ViewController.swift
// Maps iOS9
//
// Created by Alex Ngounou on 9/28/15.
// Copyright © 2015 Alex Ngounou. All rights reserved.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var myMap: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation() // starts accessing the user's position
// 18.328278, -65.318353 Playa Flamenco
let latitude: CLLocationDegrees = 18.328278
let longitude: CLLocationDegrees = -65.318353
let latDelta: CLLocationDegrees = 0.01
let longDelta: CLLocationDegrees = 0.01
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let span: MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
myMap.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "Playa de Flamenco"
annotation.subtitle = "Culebra Island"
myMap.addAnnotation(annotation)
let uilpgr = UILongPressGestureRecognizer(target: self, action: "action:")
uilpgr.minimumPressDuration = 1.0
myMap.addGestureRecognizer(uilpgr)
}
func action(gestureRecognizer: UILongPressGestureRecognizer) {
// touchpoint
let touchPoint = gestureRecognizer.locationInView(self.myMap)
// touchpoint to location
let newLocation: CLLocationCoordinate2D = myMap.convertPoint(touchPoint, toCoordinateFromView: self.myMap)
// annotation
let newAnnotation = MKPointAnnotation()
newAnnotation.coordinate = newLocation
newAnnotation.title = "New Poing"
newAnnotation.subtitle = "added via user's touch"
myMap.addAnnotation(newAnnotation)
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try this code snippet:
// Location Manager helper stuff
func initLocationManager() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.locationServicesEnabled
locationManager.requestAlwaysAuthorization()
}
// Location Manager Delegate stuff
// If failed
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if (error) {
print(error)
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
println("locations = \(locations)")
}
// authorization status
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)")
}
}
The "Debug/Location" of my iOS simulator wasn't set correctly. Once I changed this to "City Bicycle Ride", everything's good!
Thanks for the help!
Trying to figure out errors after updating to Xcode 6.3. I have a class thats getting the error 'Class has no initializers' could anyone tell me how to fix this?
class TodayViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, BWWalkthroughViewControllerDelegate {
var events: [EKEvent] = []
let eventStore = EKEventStore()
var pttCalendar: EKCalendar?
let walkthroughVC : BWWalkthroughViewController?
#IBOutlet weak var tableView: UITableView!
var dateFormatter = NSDateFormatter()
override func viewDidLoad() {
super.viewDidLoad()
requestCalendarAccess()
let firstLaunch = NSUserDefaults.standardUserDefaults().boolForKey("FirstLaunch")
if firstLaunch {
println("Not first launch.")
}
else {
showWalkthrough()
println("First launch, setting NSUserDefault.")
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "FirstLaunch")
}
self.tableView.rowHeight = 50
dateFormatter.dateFormat = "EE, MMM dd"
let dateForLabel = dateFormatter.stringFromDate(NSDate())
self.title = dateForLabel
}
You forgot the override func init()
You need an initialiser to set the value
let walkthroughVC : BWWalkthroughViewController?
Setting that as a var will remove the error. It will of course default to nil.