CoreLocation in Swift Playground - swift

I am trying to retrieve the current location of a user but in Swift Playgrounds. I have this code already but for some reason it never executes the print statements. Could anyone help?
import UIKit
import CoreLocation
import PlaygroundSupport
var str = "Hello, playground"
let locationManager = CLLocationManager()
PlaygroundPage.current.needsIndefiniteExecution = true
class GeoCoordinateDelegate: NSObject, CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
print("Most Recent Location: " + location.description)
print(location.coordinate.latitude)
print(location.coordinate.longitude)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error while updating " + error.localizedDescription)
}
}
let geoCoordinateDelegate = GeoCoordinateDelegate()
locationManager.delegate = geoCoordinateDelegate
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()

When writing CoreLocation code, it is good practice to check CLLocationManager.locationServicesEnabled() before trying to perform any location related actions.
In Swift Playgrounds (1.2 from 2017-03-21), that method returns false as CoreLocation is not available for playgrounds (yet?). I suggest to file a bug report at https://bugreport.apple.com/

Related

CLLocationManager requestLocation not calling didUpdateLocations

I have a simple CLLocationManager implementation that works in one project but not in my new project.
The code is almost identical but I cannot get the .didUpdateLocations function to call. My code is below. Any ideas why I cannot get the update to work? I'm at a loss, I've build many apps using location services and never seen this situation.
Also I have the three settings in the PLIST set correctly for Privacy-Location Always etc.
There are no errors given, it simply doesn't call .didUpdateLocations
Weather Class
class DarkSkyWeatherController: UIViewController, CLLocationManagerDelegate {
var weatherGetterDelegate: DarkSkyWeatherControllerDelegate?
var locationManager = CLLocationManager()
var lat = String()
var long = String()
func getLocation() {
// Ask for Authorisation from the User.
locationManager.requestAlwaysAuthorization()
// For use in foreground
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.startUpdatingLocation()
}
locationManager.delegate = self
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else {return}
print("locations = \(locValue.latitude) \(locValue.longitude)")
lat = String(locValue.latitude)
long = String(locValue.longitude)
getDarkSkyWeather { (fetchedInfo) in
if let myFetchedInfo = fetchedInfo {
self.weatherGetterDelegate?.getMyWeather(weather: myFetchedInfo)
}
}
}
ViewDidLoad in main window
let weather = DarkSkyWeatherController()
weather.weatherGetterDelegate = self
weather.getLocation()
Thanks for looking at this.
Without seeing your full main window code, I bet that the problem is with the scope and lifecycle of your controller:
override func viewDidLoad() {
let weather = DarkSkyWeatherController()
weather.weatherGetterDelegate = self
weather.getLocation()
// Function exits. The weather constant dies off.
// This is why you don't get callbacks.
}
Do the following, instead.
let weather = DarkSkyWeatherController()
override func viewDidLoad() {
weather.weatherGetterDelegate = self
weather.getLocation()
// Function exits, but the weather constant lives on as a field of your main ViewController. You'll get your callbacks now.
}

swift variable scope in closure wrt CLGeocoder()

Can someone please help me understand why in the following code will have output like this:
[<+37.49638550,-122.31160280> +/- 5.00m (speed 32.65 mps / course
294.26) # 7/27/16, 4:34:19 AM Eastern Daylight Time]
n/a Belmont Belmont
Belmont 1
That is, why the variable locality will have value "n/a" when printed at a specific point whereas localityVC & localityGlobal never do? Is this purely a scope issue or something to do with CLGeocoder()? Thanks
import UIKit
import MapKit
import CoreLocation
var localityGlobal: String = "n/a"
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var localityVC: String = "n/a"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
print("hello")
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations)
let userLocation: CLLocation = locations[0]
var locality: String = "n/a"
CLGeocoder().reverseGeocodeLocation(userLocation, completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("CLGeocoder.reverseGeocodeLocation() failed")
return
}
if placemarks!.count > 0 {
locality = placemarks![0].locality!
self.localityVC = placemarks![0].locality!
localityGlobal = placemarks![0].locality!
print(locality, placemarks!.count)
} else {
print("CLGeocoder.reverseGeocodeLocation() error in geocoder data")
}
})
print(locality, localityVC, localityGlobal)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In order for the above to run you also need to have:
Build Phases -> Link Binary with Libraries include
CoreLocation.framework,
Info.plist must have variables
NSLocationWhenInUseUsageDescription and
NSLocationAlwaysUsageDescription set,
Simulator -> Debug -> Location set to something like Apple, City Bicycle Ride, City Run or Freeway Drive
I'm running xcode 7.3.1 (7D1014)
This isn't a scope issue, it's a timing one. You get n/a because the closure has yet to run when that print statement is executed.
The other variables are retaining the value from a prior call.

I can't get Swift to give me a user's location

I am trying to get the user's location in Swift. Using the code below. But when I call
let currentloc = self.locationManager.location?.coordinate , it returns a nil value. The code below is above the let currentloc line in the script.
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
Make sure you:
import Corelocation + import MapKit in your class.
conform to the MKMapViewDelegate and CLLocationManagerDelegate
instantiate the locationmanager: let locationManager = CLLocationManager() in your class variables
in your viewDidLoad try:
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager. requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
Add the following delegate method to print your location:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations.last!.coordinate)
}
TLDR;
Product -> Scheme -> Edit Scheme -> Options -> Allow Location Simulation must be checked and try providing a default location, don't leave it set to "none"
When you test on simulator, you have to provide a default location, please check my answer here : https://stackoverflow.com/a/32887820/4887400

Problems with CoreLocation

For some reason I cannot seem to get the users location. I bought the iOS 9 CookBook and coped their code exactly
Here is the ViewController:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
lazy var locationManager: CLLocationManager = {
let m = CLLocationManager()
m.delegate = self
m.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
return m
}()
func locationManager(manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
//TODO: now you have access to the location. do your work
}
func locationManager(manager: CLLocationManager,
didFailWithError error: NSError) {
//TODO: handle the error
}
func locationManager(manager: CLLocationManager,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if case .AuthorizedWhenInUse = status{
manager.requestLocation()
} else {
//TODO: we didn't get access, handle this
print("No Access Granted")
}
}
#IBAction func requestLocation() {
locationManager.requestWhenInUseAuthorization()
}
}
The output in the console is:
No Access Granted
Any ideas what is going on? I have tested this on both the simulator and the device
Edit: I have added a button to the storyboard and licked that to the IBAction accordingly.
Have you added the NSLocationWhenInUseUsageDescription key to your plist? - The value should be a string describing why you want to use the users location.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Required to provide information about your location.</string>
If its all working correctly the didUpdateLocations delegate method should return an array of locations, you can print these out like so...
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for loc in locations {
print(loc)
}
}
If you want to continually monitor the location you can call manager.startUpdatingLocation() instead of manager.requestLocation()

EXC_BAD_INSTRUCTION for Map location App

I'm very new to coding so please forgive me. I'm trying to run a program on my Apple Watch that tells me my location coordinates, altitude, speed, and course.
Everything was working up to my println(userlocationInfo) line, but then I got an error at my let row = table.rowControllerAtIndex(index) as! tableRowController:
Thread 1:EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0)
By the way, what exactly does that error message mean? How can I solve an error message like this in the future by myself?
import WatchKit
import Foundation
import CoreLocation
class InterfaceController: WKInterfaceController, CLLocationManagerDelegate {
#IBOutlet weak var table: WKInterfaceTable!
var locationManager = CLLocationManager()
var userLocationInfo = [String]()
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let locationArray = locations as NSArray
let location = locationArray.lastObject as! CLLocation
userLocationInfo.removeAll(keepCapacity: true)
userLocationInfo.append("\(location.coordinate.latitude)")
userLocationInfo.append("\(location.coordinate.longitude)")
userLocationInfo.append("\(location.altitude)")
userLocationInfo.append("\(location.speed)")
userLocationInfo.append("\(location.course)")
println(userLocationInfo)
table.setNumberOfRows(userLocationInfo.count, withRowType: "tableRowController")
for (index, value) in enumerate(userLocationInfo) {
let row = table.rowControllerAtIndex(index) as! tableRowController
row.tableRowLabel.setText(value)
}
}
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
You should move your table function out of the didUpdateLocations delegate and call it after you have the location data. The didUpdateLocations will continue to run until you stop updating locations.