Как прослушать обновление массива или другую переменную в swift

#swift #swiftui

#swift #swiftui

Вопрос:

Я разработчик Android, и я начал изучать Swift. До сих пор мне удавалось делать все, что я хотел, но мне трудно слушать обновления SwiftUI .

Я реализовал сервис, который использует Firestore для чтения из базы данных. Эта служба является ObservableObject . Внутри службы у меня есть переменная, которая помечена как @Published :

 @Published var events = [Event]()
 

Я внедрил Карты Google, и я хочу извлекать эти события и что-то с ними делать, но я не знаю, как прослушивать и что-то делать, когда вызов выполнен.

Класс Карт Google:

 import SwiftUI
import GoogleMaps

struct GoogleMapsView: UIViewRepresentable {
    
    @ObservedObject var databaseService = DatabaseService()
    
    func makeUIView(context: Self.Context) -> GMSMapView {
        let camera = GMSCameraPosition.camera(withLatitude: 45.764375, longitude: 24.994272, zoom: 6.0)
        let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
        // Here I think I call .getEvents
        databaseService.getEvents()          
        
        return mapView
    }
    
    func updateUIView(_ mapView: GMSMapView, context: Context) {
        // Listen to events update and update them like this, but I don't know how...

        for event in self.databaseService.events {
            let marker = GMSMarker()
            marker.position = CLLocationCoordinate2D(latitude: event.lat, longitude: event.long)
            marker.title = event.title
            marker.snippet = event.title
            marker.map = mapView
        }
    }
}

struct GoogleMapsView_Previews: PreviewProvider {
    static var previews: some View {
        GoogleMapsView()
    }
}
 

И мое SwiftUI мнение:

 import SwiftUI

struct CommunicationsView: View {
    
    @ObservedObject var databaseService = DatabaseService()
    
    var body: some View {
        TabView() {
            GoogleMapsView()
                .edgesIgnoringSafeArea(.top)
                .tabItem {
                    Image(systemName: "leaf.fill")
                    Text("Campanii")
            }
        }.accentColor(.green)
    }
}

struct CommunicationsView_Previews: PreviewProvider {
    static var previews: some View {
        CommunicationsView()
    }
}
 

Кроме того, вот мой сервис:

 class DatabaseService : ObservableObject {

let db: Firestore
@Published var events = [Event]()

init() {
    db = Firestore.firestore()
}

func getEvents() -> Void {
    var tempoEvents = [Event]()
    db.collection(DatabaseName.CAMPAIGNS.rawValue).getDocuments { (query: QuerySnapshot?, error: Error?) in
        for document in query!.documents {
            let data = document.data()
            let title = data["title"] as? String ?? ""
            let details = data["details"] as? String ?? ""
            let lat = data["lat"] as? Double ?? 0.0
            let long = data["long"] as? Double ?? 0.0
            let date = data["date"] as? Date ?? Date()
            let author = data["author"] as? String ?? ""
            tempoEvents.append(Event(id: document.documentID, title: title, details: details, lat: lat, long: long, date: date, author: author))
        }
        
        self.events.append(contentsOf: tempoEvents)
    }
}
}
 

Ответ №1:

Вам нужно поместить

  @ObservedObject var databaseService = DatabaseService()
 

только внутри CommunicationsView с

 GoogleMapsView(events:self.databaseService.events)
 

и добавьте свойство var events = [Event]() внутри GoogleMapsView

 struct GoogleMapsView: UIViewRepresentable {
  var events = [Event]()
  ......
  for event in self.events {
  }
}
 

наконец init , в DatabaseService

 init() {
   db = Firestore.firestore()
   self.getEvents()
}
 

Комментарии:

1. Но когда мне вызывать DatabaseService.getEvents? должен ли я использовать что-то вроде. onAppear?

2. это другой способ также или внутри init

3. В моем случае карта отображается до того, как служба завершит выборку, что мне делать?

4. вам нечего делать, вот как происходит асинхронный процесс — вы можете показать загрузку, если вам нужно