I have the following setup:
MainView
API Class
The api is an Observed Object
in the main view and things are working nicely.
I would like to add into the equation LocationManager Class
, and have been able to do so as another Observed Object
and the View
updates when receives location updates.
What I would like to do, and not sure the proper way, is to pass the location to the API class
to use in a call to the API.
What is a suggested flow of doing this.
struct TempMainView: View {
@ObservedObject var api = APIFetcher()
@ObservedObject var locationMan = LocationMan()
// HOW TO MAKE API CALL ONCE LOCATION IS KNOWN
var body: some View {
Text(api.sampleText)
}
}
public class APIFetcher: ObservableObject {
@Published var sampleText: String = "Local"
init() {
self.load()
}
func load(){
//
// HIT API without LOCATION
//
let url = URL(string: "https://example.com/api/nolocation")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
do {
if let d = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let newString = try decoder.decode(String.self, from: d)
DispatchQueue.main.async {
self.sampleText = newString
}
}
} catch {
print ("Error - \(error)")
}
}.resume()
}
func loadWithCoordinates(){
let coordinates: CLLocationCoordinate2D
//
// HIT API with LOCATION
// (HOW TO CALL THIS WHEN THERE IS A KNOWN LOCATION)
//
let stringFromCoordinates = String("\(coordinates.longitude),\(coordinates.latitude)")
let url = URL(string: "https://example.com/api/location/\(stringFromCoordinates)")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
do {
if let d = data {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
let newString = try decoder.decode(String.self, from: d)
DispatchQueue.main.async {
self.sampleText = newString
}
}
} catch {
print ("Error - \(error)")
}
}.resume()
}
}
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
@Published var location: CLLocation? {
willSet { objectWillChange.send() }
}
override init() {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
//
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
self.location = location
//
}
}
I would prolly just listen for emitted Notifications. For clarity I removed the failing URL response handling code:
struct TempMainView: View {
@ObservedObject var api = APIFetcher()
var locationMan = LocationManager()
let locationChange = NotificationCenter.default.publisher(for: .location)
var body: some View {
Text(api.sampleText)
.onReceive(locationChange) { note in
let loc = note.userInfo!["location"]! as! CLLocation
self.api.loadWithCoordinates(coordinates: loc.coordinate)
}
}
}
public class APIFetcher: ObservableObject {
@Published var sampleText: String = "Local"
init() {
self.load()
}
func load(){
let url = URL(string: "https://example.com/api/nolocation")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
DispatchQueue.main.async {
self.sampleText = "loaded w/o location"
}
}.resume()
}
func loadWithCoordinates(coordinates: CLLocationCoordinate2D){
let stringFromCoordinates = String("\(coordinates.longitude),\(coordinates.latitude)")
let url = URL(string: "https://example.com/api/location/\(stringFromCoordinates)")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
DispatchQueue.main.async {
self.sampleText = "loaded from \(stringFromCoordinates)"
}
}.resume()
}
}
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
override init() {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
extension Notification.Name {
static let location = Notification.Name("location")
}
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let note = Notification(name: .location, object: nil, userInfo: ["location": location])
NotificationCenter.default.post(note)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.