简体   繁体   中英

How to pass data between two Observed Objects in SwiftUI

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.

1 My View

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)
        
    }
    
}

2 My API Class

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()
    }
}

3 Location Manager Class

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM