I am wondering what can the be reason of my issue. I am using core location in order to get the my coordinates location, which I use in the network method as a URLQueryItem in order to get a response from the API. But the console output shows that the latitude query and longitude query are both equal to 0 while I have my a latitude and longitude value. I use the network method inside my viewdidload.
Thanks for all responses and explanations.
var queryLattitudeItem : Double = 0
var queryLongitudeItem : Double = 0
func network () {
let configuration = URLSessionConfiguration.default
configuration.waitsForConnectivity = true
let session = URLSession(configuration: configuration)
guard let urls = URL(string:"https://api.yelp.com/v3/businesses/search") else { return }
var urlcomponent = URLComponents(string: "\(urls)")
let queryLat = URLQueryItem(name:"latitude" , value: "\(queryLattitudeItem)")
let queryLong = URLQueryItem(name: "longitude", value: "\(queryLongitudeItem)")
let queryItemterm = URLQueryItem(name: "term", value: "restaurant")
let queryLimit = URLQueryItem(name: "limit", value: "10")
urlcomponent?.queryItems = [queryItemterm,queryLat,queryLong,queryLimit]
print(urlcomponent!)
print(queryLat)
print(queryLong)
var request = URLRequest(url: urlcomponent!.url!)
request.httpMethod = "GET"
request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let task = session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse {
print(response)
} else{
print("error")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[locations.count - 1]
if location.horizontalAccuracy > 0 {
locationManager.stopUpdatingLocation()
print("\(location.coordinate.longitude), \(location.coordinate.latitude)")
}
let latitude : Double = (location.coordinate.latitude)
let longitude : Double = location.coordinate.longitude
print("This is lat: \(latitude), et long\(longitude)")
queryLattitudeItem = latitude
queryLongitudeItem = longitude
}
Console output
https://api.yelp.com/v3/businesses/search?term=restaurant&latitude=0.0&longitude=0.0&limit=10
latitude=0.0
longitude=0.0
-73.984638, 40.759211
This is lat: 40.759211, et long-73.984638
<NSHTTPURLResponse: 0x600003a91ec0> { URL: https://api.yelp.com/v3/businesses/search?term=restaurant&latitude=0.0&longitude=0.0&limit=10 } { Status Code: 200, Headers {
"Accept-Ranges" = (
One stylistic thing I'd do with your code is utilize some sort of structure for storing strings so they're not littered throughout your code. When something fouls up, you can go to one spot to debug it rather than plowing through a bunch of code. Here, I store the string in an enum as a static let (b/c I hate rawValues):
enum Endpoint {
static let yelp = "https://api.yelp.com/v3/businesses/search"
}
Next, I'd ditch the var declarations for latitude and longitude:
var queryLattitudeItem : Double = 0 // 🚫 nuke
var queryLongitudeItem : Double = 0 // 🚫 nuke
Instead, I'd update your network request method to accept a CLLocationCoordinate2D straight from the delegate method, like so:
func getYelpInfo(for coordinate: CLLocationCoordinate2D) {
// omitted your networking code...this is just the URL creation code
var components = URLComponents(string: Endpoint.yelp)
let queryLat = URLQueryItem(name: "latitude", value: String(coordinate.latitude))
let queryLong = URLQueryItem(name: "longitude", value: String(coordinate.latitude))
let queryLimit = URLQueryItem(name: "limit", value: "10")
components?.queryItems = [queryLat, queryLong, queryLimit]
// You could use a guard statement here if you want to exit out, too
if let url = components?.url {
var request = URLRequest(url: url)
// do your networking request
}
print(components!.url!.absoluteString)
}
Next, in your didUpdateLocations, I'd call the updated method, like so:
getYelpInfo(for: location.coordinate)
Your updated method looks like this:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[locations.count - 1]
if location.horizontalAccuracy > 0 {
locationManager.stopUpdatingLocation()
getYelpInfo(for: location.coordinate)
print("\(location.coordinate.longitude), \(location.coordinate.latitude)")
}
}
Related
I have tried to make a separate class for the location functionality (separate swift file in the Watchkit Exension folder) and I want to use the location instance of that class in the InterfaceController class to track the location of the user. But, xcode gets stuck and I also cannot deploy and test the application. I do not know what the reason is.
Here is the location code and the InterfaceController class:
The whole project is here: https://filebin.net/s40xlqzeukfwc39w
I hope you can help me out since I am still a beginner in terms of Swift and WatchKit. Thank you very much.
import WatchKit
import Foundation
import CoreLocation
class LocationOutside{
var locationManager: CLLocationManager = CLLocationManager()
init(){
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.delegate = (self as! CLLocationManagerDelegate)
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let currentLoc = locations[0]
let lat = currentLoc.coordinate.latitude
let long = currentLoc.coordinate.longitude
print(lat)
print(long)
}
func locationManager(_manager: CLLocationManager,didFailWithError error: Error){
if let locationErr = error as? CLError{
switch locationErr{
case CLError.locationUnknown:
print("unknown location")
case CLError.denied:
print("denied")
default:
print("another type of location error")
}
}else{
print("other error: ", error.localizedDescription)
}
}
}
import WatchKit
import Foundation
import CoreLocation
import HealthKit
import AVFoundation
import CoreMotion
let hrType:HKQuantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
// Date will be constructed in database --> server side
class InterfaceController: WKInterfaceController,AVAudioRecorderDelegate{
var saveUrl: URL?
var outDoorLocation = LocationOutside.init()
// to conduct permission to retrieve location data
var locationManager: CLLocationManager = CLLocationManager()
// Outlets for testing
#IBOutlet weak var button: WKInterfaceButton!
#IBOutlet weak var furtherSigLabels: WKInterfaceLabel!
var recordingSession : AVAudioSession!
var audioRecorder : AVAudioRecorder!
var settings = [String : Any]()
// distinguish start recording heartbeat
var isRecording = false
//For workout session
let healthStore = HKHealthStore()
var session: HKWorkoutSession?
var currentQuery: HKQuery?
var filename: String?
let motionManager = CMMotionManager()
let queue = OperationQueue()
var gravityStr = ""
var userAccelerStr = ""
var rotationRateStr = ""
var attitudeStr = ""
var movement = ""
var manualLat: Double = 0.0
var manualLong: Double = 0.0
var heartRateVal: Double = 0.0
var prev_grav_z: Double = 0.0
var prev_acc_z: Double = 0.0
var grav_x:Double = 0.0
var grav_y:Double = 0.0
var grav_z:Double = 0.0
var acc_x:Double = 0.0
var acc_y:Double = 0.0
var acc_z:Double = 0.0
var sendOrNot:Bool = false
override func awake(withContext context: Any?) {
super.awake(withContext: context)
/**
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestLocation()
*/
// managing authorization
let healthService:HealthDataService = HealthDataService()
healthService.authorizeHealthKitAccess { (success, error) in
if success {
print("HealthKit authorization received.")
} else {
print("HealthKit authorization denied!")
if error != nil {
print("\(String(describing: error))")
}
}
}
motionManager.deviceMotionUpdateInterval = 0.5
}
/**
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let currentLoc = locations[0]
let lat = currentLoc.coordinate.latitude
let long = currentLoc.coordinate.longitude
manualLat = lat
manualLong = long
/**
let request = NSMutableURLRequest(url: NSURL(string: "http://147.46.242.219/addgps.php")! as URL)
request.httpMethod = "POST"
let postString = "a=\(lat)&b=\(long)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")
}
task.resume()
*/
}
*/
/**
func locationManager(_: CLLocationManager, didFailWithError error: Error) {
let err = CLError.Code(rawValue: (error as NSError).code)!
switch err {
case .locationUnknown:
break
default:
print(err)
}
}
*/
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
motionManager.startDeviceMotionUpdates(to: queue) { (deviceMotion: CMDeviceMotion?, error: Error?) in
if error != nil {
print("Encountered error: \(error!)")
}
if deviceMotion != nil {
self.grav_x = (deviceMotion?.gravity.x)!
self.grav_y = (deviceMotion?.gravity.y)!
self.grav_z = (deviceMotion?.gravity.z)!
self.gravityStr = String(format: "grav_x: %.2f, grav_y: %.2f, grav_z: %.2f" ,
self.grav_x,
self.grav_y,
self.grav_z)
if self.prev_grav_z == 0.0 {
self.prev_grav_z = self.grav_z
self.sendOrNot = true
}
else{
if (self.grav_z - self.prev_grav_z) <= -0.25{
//print("Gravity: ",self.grav_z, self.prev_grav_z)
self.sendOrNot = true
}
else{
self.sendOrNot = false
}
self.prev_grav_z = self.grav_z
}
//self.sendData(x: self.gravityStr)
// print(self.gravityStr)
self.acc_x = (deviceMotion?.userAcceleration.x)!
self.acc_y = (deviceMotion?.userAcceleration.y)!
self.acc_z = (deviceMotion?.userAcceleration.z)!
self.userAccelerStr = String(format: "acc_x: %.2f, acc_y: %.2f, acc_z: %.2f" ,
self.acc_x,
self.acc_y,
self.acc_z)
if (self.acc_z - self.prev_acc_z) <= -0.2{
//print("Accelero_z: ",self.acc_z, self.prev_acc_z)
self.sendOrNot = true
}
else{
self.sendOrNot = false
}
self.prev_acc_z = self.acc_z
self.rotationRateStr = String(format: "rota_x: %.2f, rota_y: %.2f, rota_z: %.2f" ,
(deviceMotion?.rotationRate.x)!,
(deviceMotion?.rotationRate.y)!,
(deviceMotion?.rotationRate.z)!)
//self.sendData(x: self.rotationRateStr)
//print(self.rotationRateStr)
self.attitudeStr = String(format: "atti_roll: %.1f, atti_pitch: %.1f, atti_yaw: %.1f" ,
(deviceMotion?.attitude.roll)!,
(deviceMotion?.attitude.pitch)!,
(deviceMotion?.attitude.yaw)!)
//self.sendData(x: self.attitudeStr)
//print(self.attitudeStr)
//self.movement = self.gravityStr + self.userAccelerStr + self.rotationRateStr + self.attitudeStr
if self.sendOrNot{
//print("Falling motion detected!")
self.movement = "\(self.gravityStr), \(self.userAccelerStr), \(self.rotationRateStr), \(self.attitudeStr), \("_1")"
}
else{
self.movement = "\(self.gravityStr), \(self.userAccelerStr), \(self.rotationRateStr), \(self.attitudeStr), \("_0")"
}
//print(self.movement)
self.sendOrNot = false
}
}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
motionManager.stopDeviceMotionUpdates()
}
/**
func sendData(x:String){
let request = NSMutableURLRequest(url: NSURL(string: "http://147.46.242.219/addgyro2.php")! as URL)
request.httpMethod = "POST"
let postString = "a=\(x)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")
}
task.resume()
}
*/
/**
func getDocumentsDirectory() -> URL
{
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
func getFileUrl() -> URL
{
let filePath = getDocumentsDirectory().appendingPathComponent(filename!)
return filePath
}
func startRecording(){
let audioSession = AVAudioSession.sharedInstance()
do{
audioRecorder = try AVAudioRecorder(url: getFileUrl(),
settings: settings)
audioRecorder.delegate = self
audioRecorder.prepareToRecord()
audioRecorder.record(forDuration: 5.0)
}
catch {
finishRecording(success: false)
}
do {
try audioSession.setActive(true)
audioRecorder.record()
} catch {
}
}
func finishRecording(success: Bool) {
audioRecorder.stop()
audioRecorder = nil
if success {
print(success)
} else {
audioRecorder = nil
print("Somthing Wrong.")
}
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
if !flag {
finishRecording(success: false)
}
}
*/
// generate a short unique id
struct ShortCodeGenerator {
private static let base62chars = [Character]("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
private static let maxBase : UInt32 = 62
static func getCode(withBase base: UInt32 = maxBase, length: Int) -> String {
var code = ""
for _ in 0..<length {
let random = Int(arc4random_uniform(min(base, maxBase)))
code.append(base62chars[random])
}
return code
}
}
// Getting the address from longitude and latitude
func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
let lat: Double = Double("\(pdblLatitude)")!
//21.228124
let lon: Double = Double("\(pdblLongitude)")!
//72.833770
let ceo: CLGeocoder = CLGeocoder()
center.latitude = lat
center.longitude = lon
let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude)
ceo.reverseGeocodeLocation(loc, completionHandler:
{(placemarks, error) in
if (error != nil)
{
//print("reverse geodcode fail: \(error!.localizedDescription)")
}
let pm = placemarks! as [CLPlacemark]
if pm.count > 0 {
let pm = placemarks![0]
//print(pm.country)
//print(pm.locality)
//print(pm.subLocality)
//print(pm.thoroughfare)
//print(pm.postalCode)
//print(pm.subThoroughfare)
var addressString : String = ""
if pm.subLocality != nil {
addressString = addressString + pm.subLocality! + ", "
}
if pm.thoroughfare != nil {
addressString = addressString + pm.thoroughfare! + ", "
}
if pm.locality != nil {
addressString = addressString + pm.locality! + ", "
}
if pm.country != nil {
addressString = addressString + pm.country! + ", "
}
if pm.postalCode != nil {
addressString = addressString + pm.postalCode! + " "
}
//print(addressString)
}
})
}
#IBAction func manualBtnPressed() {
// manual reporting functionality
// generating 6 character long unique id
let uniqueId = ShortCodeGenerator.getCode(length: 6)
let txtMsg = "I am student \(uniqueId). I need help!"
print(txtMsg)
// Getting the address
if manualLat != 0.0 && manualLong != 0.0 {
var latStr = String(format:"%.2f",manualLat)
var longStr = String(format:"%.2f",manualLong)
getAddressFromLatLon(pdblLatitude: latStr, withLongitude: longStr)
let request = NSMutableURLRequest(url: NSURL(string: "http://147.46.242.219/addmanual.php")! as URL)
request.httpMethod = "POST"
let postString = "a=\(manualLat)&b=\(manualLong)&c=\(txtMsg)"
print(postString)
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
//print("error=\(error)")
return
}
//print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
//print("responseString = \(responseString)")
}
task.resume()
}
}
// when button clicked label is shown
#IBAction func btnPressed() {
if(!isRecording){
let stopTitle = NSMutableAttributedString(string: "Stop Recording")
stopTitle.setAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], range: NSMakeRange(0, stopTitle.length))
button.setAttributedTitle(stopTitle)
isRecording = true
startWorkout() //Start workout session/healthkit streaming
}else{
let exitTitle = NSMutableAttributedString(string: "Start Recording")
exitTitle.setAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], range: NSMakeRange(0, exitTitle.length))
button.setAttributedTitle(exitTitle)
isRecording = false
healthStore.end(session!)
}
}
}
extension InterfaceController: HKWorkoutSessionDelegate{
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
switch toState {
case .running:
//print(date)
if let query = heartRateQuery(date){
self.currentQuery = query
healthStore.execute(query)
}
//Execute Query
case .ended:
//Stop Query
healthStore.stop(self.currentQuery!)
session = nil
default:
print("Unexpected state: \(toState)")
}
}
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
//Do Nothing
}
func startWorkout(){
// If a workout has already been started, do nothing.
if (session != nil) {
return
}
// Configure the workout session.
let workoutConfiguration = HKWorkoutConfiguration()
workoutConfiguration.activityType = .running
workoutConfiguration.locationType = .outdoor
do {
session = try HKWorkoutSession(configuration: workoutConfiguration)
session?.delegate = self
} catch {
fatalError("Unable to create workout session")
}
healthStore.start(self.session!)
//print("Start Workout Session")
// Here audio?
/**
if audioRecorder == nil {
print("Pressed")
filename = NSUUID().uuidString+".wav"
self.startRecording()
} else {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = URL(fileURLWithPath: path)
print("Filename\(filename!)")
let pathPart = url.appendingPathComponent(filename!)
let filePath = pathPart.path
let request = NSMutableURLRequest(url: NSURL(string: "http://147.46.242.219/addsound.php")! as URL)
request.httpMethod = "POST"
let audioData = NSData(contentsOfFile: filePath)
print("Result is\(getFileUrl().path)")
print("Binary data printing")
print(audioData)
let postString = "a=\(audioData)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")
}
task.resume()
print("Pressed2")
self.finishRecording(success: true)
}
*/
}
func heartRateQuery(_ startDate: Date) -> HKQuery? {
let datePredicate = HKQuery.predicateForSamples(withStart: startDate, end: nil, options: .strictEndDate)
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates:[datePredicate])
let heartRateQuery = HKAnchoredObjectQuery(type: hrType, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in
//Do nothing
}
heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in
guard let samples = samples as? [HKQuantitySample] else {return}
DispatchQueue.main.async {
guard let sample = samples.first else { return }
// after extraction of bpm value conversion to double
let value = sample.quantity.doubleValue(for: HKUnit(from: "count/min"))
//print("Type of value is +\(type(of:value))")
let request = NSMutableURLRequest(url: NSURL(string: "http://147.46.242.219/addall.php")! as URL)
request.httpMethod = "POST"
//print(self.movement)
//let randomStr = 42.0
let postString = "gps_x=\(self.manualLat)&gps_y=\(self.manualLong)&a=\(self.movement)&hr=\(value)"
//print(postString)
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
//print("error=\(error)")
return
}
//print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
//print("responseString = \(responseString)")
}
task.resume()
//print("This line is executed!")
//print(String(UInt16(value)))
}
}
return heartRateQuery
}
}
class HealthDataService {
internal let healthKitStore:HKHealthStore = HKHealthStore()
init() {}
func authorizeHealthKitAccess(_ completion: ((_ success:Bool, _ error:Error?) -> Void)!) {
let typesToShare = Set([hrType])
let typesToSave = Set([hrType])
healthKitStore.requestAuthorization(toShare: typesToShare, read: typesToSave) { (success, error) in
completion(success, error)
}
}
}
After I tried running your project in Xcode on Apple Watch, it crashed and the console said Could not cast value of type 'BullyingDetection_WatchKit_Extension.LocationOutside' (0x92ca0) to 'CLLocationManagerDelegate' (0x6b433f84).
On line 20 of your LocationOutside class, locationManager.delegate = (self as! CLLocationManagerDelegate) will have to be locationManager.delegate = self and the class will need to conform to the CLLocationManagerManagerDelegate protocol which also requires inheriting from NSObject:
class LocationOutside: NSObject, CLLocationManagerDelegate {
}
This should lead you in the right direction.
It may help to also read about delegation here https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID276.
I am using GoogleMaps to draw route. What I want to do is when user travels on that route remove the line which is already travelled(Like Uber does). I guess we can do it with removing the points from the polyline and redraw it. Is it the correct approach?
How can I know that those points are travelled and need to update the path?
1) Create Globle Variable
var demoPolyline = GMSPolyline()
var demoPolylineOLD = GMSPolyline()
// Set Destination Location Cordinates
var destinationLocation = CLLocation(latitude: 23.072837, longitude: 72.516455)
2) Use CLLocationManagerDelegate Method For update current location
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
let originalLoc: String = "\(location.coordinate.latitude),\(location.coordinate.longitude)"
let destiantionLoc: String = "\(destinationLocation.coordinate.latitude),\(destinationLocation.coordinate.longitude)"
let latitudeDiff: Double = Double(location.coordinate.latitude) - Double(destinationLocation.coordinate.latitude)
let longitudeDiff: Double = Double(location.coordinate.longitude) - Double(destinationLocation.coordinate.longitude)
let waypointLatitude = location.coordinate.latitude - latitudeDiff
let waypointLongitude = location.coordinate.longitude - longitudeDiff
getDirectionsChangedPolyLine(origin: originalLoc, destination: destiantionLoc, waypoints: ["\(waypointLatitude),\(waypointLongitude)"], travelMode: nil, completionHandler: nil)
}
3) Create Method For Draw and update Polyline on Google map
func getDirectionsChangedPolyLine(origin: String!, destination: String!, waypoints: Array<String>!, travelMode: AnyObject!, completionHandler: ((_ status: String, _ success: Bool) -> Void)?)
{
DispatchQueue.main.asyncAfter(deadline: .now()) {
if let originLocation = origin {
if let destinationLocation = destination {
var directionsURLString = "https://maps.googleapis.com/maps/api/directions/json?" + "origin=" + originLocation + "&destination=" + destinationLocation
if let routeWaypoints = waypoints {
directionsURLString += "&waypoints=optimize:true"
for waypoint in routeWaypoints {
directionsURLString += "|" + waypoint
}
}
directionsURLString = directionsURLString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
let directionsURL = NSURL(string: directionsURLString)
DispatchQueue.main.async( execute: { () -> Void in
let directionsData = NSData(contentsOf: directionsURL! as URL)
do{
let dictionary: Dictionary<String, AnyObject> = try JSONSerialization.jsonObject(with: directionsData! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String, AnyObject>
let status = dictionary["status"] as! String
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<String, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<String, AnyObject>
let route = self.overviewPolyline["points"] as! String
let path: GMSPath = GMSPath(fromEncodedPath: route)!
self.demoPolylineOLD = self.demoPolyline
self.demoPolylineOLD.strokeColor = UIColor.blue
self.demoPolylineOLD.strokeWidth = 3.0
self.demoPolylineOLD.map = self.mapView
self.demoPolyline.map = nil
self.demoPolyline = GMSPolyline(path: path)
self.demoPolyline.map = self.mapView
self.demoPolyline.strokeColor = UIColor.blue
self.demoPolyline.strokeWidth = 3.0
self.demoPolylineOLD.map = nil
} else {
self.getDirectionsChangedPolyLine(origin: origin, destination: destination, waypoints: waypoints, travelMode: travelMode, completionHandler: completionHandler)
}
} catch {
self.getDirectionsChangedPolyLine(origin: origin, destination: destination, waypoints: waypoints, travelMode: travelMode, completionHandler: completionHandler)
}
})
} else {
print("Destination Location Not Found")
}
} else {
print("Origin Location Not Found")
}
}
}
This is working on my live project
I hope this will work for everybody
I'm putting JSON data into a table view, and I'm trying to parse through the data using a for loop. However, when the loop is done parsing through the JSON data and has placed the 20 items into the table view, it restarts the process, parses the JSON again, and the same data appears in the table view again. This process repeats for a long time as well.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else{ return }
var searchURL = NSString(format: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%f,%f&radius=50000&types=night_club&key=MY_API_KEY", (location.coordinate.latitude),(location.coordinate.longitude)) as? String
var cityInfo = NSString(format: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%f,%f&radius=50000&types=locality&key=MY_API_KEY", (location.coordinate.latitude),(location.coordinate.longitude)) as? String
manager.stopUpdatingLocation()
getCityInfo(url: cityInfo!)
callAlamo(url: searchURL!)
}
func getCityInfo(url:String){
Alamofire.request(url).responseJSON(completionHandler: { response in
self.parseJSON(JSONData: response.data!)
})
}
func parseJSON(JSONData:Data){
do{
var readableJSON = try JSONSerialization.jsonObject(with: JSONData) as! JSONStandard
// PARSING THROUGH JSON DATA TO GET CITY NAME
if let results = readableJSON["results"] as? [JSONStandard]{
for i in 0..<results.count{
let item = results[i]
let cityInfo = item["name"] as! String
cityName.append(cityInfo)
// GETTING PHOTO URL WITH photo_reference AND PUTTING THEM INTO imageURL ARRAY
if let photos = item["photos"] as? [JSONStandard]{
for j in 0..<photos.count{
let photo = photos[j] as JSONStandard
let photoRef = photo["photo_reference"] as! String
let photoURL = NSString(format: "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=%#&key=MY_API_KEY", photoRef) as? String
cityURL.append(photoURL!)
}
}
}
}
cityLabel.text = cityName[0]
cityImage.sd_setImage(with: URL(string:cityURL[0]), placeholderImage: #imageLiteral(resourceName: "cityOfCalgary"))
}
catch{
print(error)
}
}
func callAlamo(url:String){
Alamofire.request(url).responseJSON(completionHandler: { response in
self.parseData(JSONData: response.data!)
})
}
func parseData(JSONData:Data){
do{
var myReadableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
// PARSING THROUGH JSON DATA TO GET NAMES AND PICTURES OF PLACES, THEN PUTTING
// THEM INTO AN ARRAY AND OUTPUTTING THEM ONTO TABLE VIEW CELL
if let results = myReadableJSON["results"] as? [JSONStandard]{
for i in 0..<results.count{ //results.count = 20
let item = results[i]
let names = item["name"] as! String
placeNames.append(names)
// GETTING PHOTO URL WITH photo_reference AND PUTTING THEM INTO imageURL ARRAY
if let photos = item["photos"] as? [JSONStandard]{
let photoRef = photos[0]
let photoReference = photoRef["photo_reference"] as! String
let photoURL = NSString(format: "https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=%#&key=MY_API_KEY", photoReference) as? String
imageURL.append(photoURL!)
}
if let geometry = item["geometry"] as? JSONStandard{
if let location = geometry["location"] as? [String : Any]{
let latitude = location["lat"] as? Double
let longitude = location["lng"] as? Double
}
}
}
}
// SHOULD BE PLACED AT THE END OF GATHERING DATA
locationManager.stopUpdatingLocation()
self.tableView.reloadData()
}
catch{
print(error)
}
}
UPDATE:
As vadian had mentioned in one of his first comments, parseData() was getting called multiple times. So I added
locationManager.delegate = nil
after I stop updating the location in the locationManager delegate function.
`
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else{ return }
searchURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(location.coordinate.latitude),\(location.coordinate.longitude)&radius=50000&types=night_club&key=MY_API_KEY"
cityInfo = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(location.coordinate.latitude),\(location.coordinate.longitude)&radius=50000&types=locality&key=MY_API_KEY"
locationManager.stopUpdatingLocation()
locationManager.delegate = nil
getCityInfo(url: cityInfo)
callAlamo(url: searchURL)
}
`
Everything else remains the same after this.
As I suspected you are calling parseData multiple times. A solution is to stop monitoring the location right in the delegate method.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let searchURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(location.coordinate.latitude),\(location.coordinate.longitude)&radius=50000&types=night_club&key=AIzaSyA2LQsGK_I1ETnKPGbjWgFW9onZlHog6dg"
// var cityInfo = NSString(format: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%f,%f&radius=50000&types=locality&key=AIzaSyA2LQsGK_I1ETnKPGbjWgFW9onZlHog6dg", (location?.coordinate.latitude)!,(location?.coordinate.longitude)!) as? String
manager.stopUpdatingLocation()
callAlamo(url: searchURL)
}
I edited the body of the method a bit to avoid all question and exclamation marks.
Side-note: Basically do not annotate types the compiler can infer.
The following app should get the user's current location and then display the Name and Temperature of that location using OpenWeatherMap.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var location: UILabel!
#IBOutlet weak var temperature: UILabel!
var locationManager: CLLocationManager = CLLocationManager()
var startLocation: CLLocation!
func extractData(weatherData: NSData) {
let json = try? NSJSONSerialization.JSONObjectWithData(weatherData, options: []) as! NSDictionary
if json != nil {
if let name = json!["name"] as? String {
location.text = name
}
if let main = json!["main"] as? NSDictionary {
if let temp = main["temp"] as? Double {
temperature.text = String(format: "%.0f", temp)
}
}
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let latestLocation: AnyObject = locations[locations.count - 1]
let lat = latestLocation.coordinate.latitude
let lon = latestLocation.coordinate.longitude
// Put together a URL With lat and lon
let path = "http://api.openweathermap.org/data/2.5/weather?lat=\(lat)&lon=\(lon)&appid=2854c5771899ff92cd962dd7ad58e7b0"
print(path)
let url = NSURL(string: path)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
self.extractData(data!)
})
}
task.resume()
}
func locationManager(manager: CLLocationManager,
didFailWithError error: NSError) {
}
override func viewDidLoad() {
super.viewDidLoad()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
startLocation = nil
}
}
I've been learning how to get data from OpenWeatherMap following this tutorial:
https://www.youtube.com/watch?v=r-LZs0De7_U
The app crashes at:
self.extractData(data!)
as data is equal to nil, this shouldn't be happening as when I copy and paste the printed path into my web browser, the data is there. I'm sure I've followed the tutorial correctly, so what's the problem and how do I fix it?
The problem is with Transport Security - which causes issues for lots of us. Here's one of the SO answers explaining how to resolve it Transport security has blocked a cleartext HTTP
If you make the setting in your plist - set the NSAllowsArbitraryLoads key to YES under NSAppTransportSecurity dictionary in your .plist file - then it works.
I have a question about periodic updating my location,with NSTimeri call periodically
:
func timerUpdate() {
func locationManager1 (manager: CLLocationManager , didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = (manager.location?.coordinate)!
_ = locManager.location!
print(locValue)
}
//self.locManager.startUpdatingLocation()
self.loctimestamp.text = "\(locManager.location!.timestamp)"
// Check if the user allowed authorization
//let loc = CLLocation()
let kur = 999
let lat = locManager.location!.coordinate.latitude
let lon = locManager.location!.coordinate.longitude
let acc = locManager.desiredAccuracy
let age = 3
let urlComponents = NSURLComponents(string: "http://example.com/track/gps.php?kur=\(kur)&lon=\(lon)&lat=\(lat)&acc=\(acc)&age=\(age)")
let urler = urlComponents!.URL
let url = urler
let request = NSURLRequest(URL: url!)
//let html = NSData(contentsOfURL: url!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let html = NSString(data: (data)!, encoding: NSUTF8StringEncoding)
print(html)
print("Response: \(response)")
self.debug.text = ("Response: \(response)")
self.debug1.text = String(html)
}
)
task.resume()
Status.text = "an"
//locManager.stopUpdatingLocation()
}
this work fine after here come the viewdidload with
self.locManager.startUpdatingLocation()
if #available(iOS 8.0, *) {
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Authorized)
{
//locManager.distanceFilter.hashValue:100
locManager.pausesLocationUpdatesAutomatically = false
self.locManager.delegate = self
self.locManager.desiredAccuracy = kCLLocationAccuracyBest
self.locManager.requestAlwaysAuthorization()
// self.mapView.showUserLocation = true
if #available(iOS 9.0, *) {
locManager.allowsBackgroundLocationUpdates = true
} else {
// Fallback on earlier versions
}
and so on ,
but i just become the location from when i start the app
startUpdateLocation run but why a receive just an coordinate.timestamp one for locManager.location!.coordinate.latitude
i taught the location will be updated if location is changed
I Found the simple Solution just initiate a new CLLocationManager()
func timerUpdate() {
->>> let loco = CLLocationManager() !!!
// Check if the user allowed authorization
loctimestamp.text = "\(loco.location!.timestamp)"
//let loc = CLLocation()
let kur = 999
let lat = loco.location!.coordinate.latitude
let lon = loco.location!.coordinate.longitude
let acc = loco.desiredAccuracy
let age = 3
let urlComponents = NSURLComponents(string: "http://example.com/track/gps.php?kur=\(kur)&lon=\(lon)&lat=\(lat)&acc=\(acc)&age=\(age)")
let urler = urlComponents!.URL
let url = urler
let request = NSURLRequest(URL: url!)
//let html = NSData(contentsOfURL: url!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let html = NSString(data: (data)!, encoding: NSUTF8StringEncoding)
print(html)
print("Response: \(response)")
self.debug.text = ("Response: \(response)")
self.debug1.text = String(html)
}
)
task.resume()
Status.text = "an"
//locManager.stopUpdatingLocation()
}
`