首页 > 解决方案 > 你能从 SwiftUI 中的 MapKit 数据库中获取纬度和经度吗

问题描述

我正在开发一个 SwiftUI 项目,并希望将地图放置在使用存储在 Firestore 中的坐标的视图中。Apple 在 SwiftUI 中的 MapKit 示例在 @State 属性中使用静态纬度和经度参数,然后将该属性绑定到 Map() 视图。

struct BusinessMapView: View {
    @State private var region: MKCoordinateRegion = {
        var mapCoordinates = CLLocationCoordinate2D(latitude: 44.621754, longitude: -66.475873)
        var mapZoomLevel = MKCoordinateSpan(latitudeDelta: 5.00, longitudeDelta: 5.00)
        var mapRegion = MKCoordinateRegion(center: mapCoordinates, span: mapZoomLevel)
        return mapRegion
    }()
            
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

我想做的是以下内容,但显然这是不允许的,因为您无法访问另一个属性中的其他属性。

struct BusinessMapView: View {
    @ObservedObject var businessAddressRowViewModel: BusinessAddressRowViewModel

    @State private var region: MKCoordinateRegion = {
        var mapCoordinates = CLLocationCoordinate2D(latitude: businessAddressRowViewModel.businessAddress.latitude, longitude: businessAddressRowViewModel.businessAddress.longitude)
        var mapZoomLevel = MKCoordinateSpan(latitudeDelta: 5.00, longitudeDelta: 5.00)
        var mapRegion = MKCoordinateRegion(center: mapCoordinates, span: mapZoomLevel)
        return mapRegion
    }()
            
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

所以我的问题是,有没有办法从数据库中为 SwiftUI 中的 Map() 设置坐标,或者是使用静态值作为纬度和经度的唯一选择?

添加编辑以获取更多信息

class BusinessAddressRowViewModel: ObservableObject, Identifiable {
    
    // Properties
    var id: String = ""
    
    public static let shared = BusinessAddressRowViewModel()
    
    // Published Properties
    @Published var businessAddress: BusinessAddress
    
    // Combine Cancellable
    private var cancellables = Set<AnyCancellable>()
    
    
    // Initializer
    init(businessAddress: BusinessAddress) {
        self.businessAddress = businessAddress
        self.startCombine()
    }
    
    // Starting Combine
    func startCombine() {
        // Get Bank Account
        $businessAddress
            .receive(on: RunLoop.main)
            .compactMap { businessAddress in
                businessAddress.id
            }
            .assign(to: \.id, on: self)
            .store(in: &cancellables)
    }
}

共享属性给出了一个错误,指出缺少参数 businessAddress。

数据来自此处的 Firebase Firestore。

class BusinessAddressRepository: ObservableObject {
    let db = Firestore.firestore()
    private var snapshotListener: ListenerRegistration?
    
    @Published var businessAddresses = [BusinessAddress]()
    
    init() {
        startSnapshotListener()
    }
        
    func startSnapshotListener() {
        // Get the currentUserUid
        guard let currentUserId = Auth.auth().currentUser else {
            return
        }
        
        if snapshotListener == nil {
            // Add a SnapshotListener to the BusinessAddress Collection.
            self.snapshotListener = db.collection(FirestoreCollection.users).document(currentUserId.uid).collection(FirestoreCollection.businessAddresses).addSnapshotListener { (querySnapshot, error) in
                // Check to see if an error occured and print it. IMPLEMENT ERROR HANDLING LATER
                if let error = error {
                    print("Error getting documents: \(error)")
                } else {
                    print("BusinessAddressRepository - snapshotListener called")
                    
                    // Check to make sure the Collection contains Documents
                    guard let documents = querySnapshot?.documents else {
                        print("No Business Addresses.")
                        return
                    }
                    
                    // Documents exist.
                    self.businessAddresses = documents.compactMap { businessAddress in
                        do {
                            return try businessAddress.data(as: BusinessAddress.self)
                        } catch {
                            print(error)
                        }
                        return nil
                    }
                }
            }
        }
    }

    func stopSnapshotListener() {
        if snapshotListener != nil {
            snapshotListener?.remove()
            snapshotListener = nil
        }
    }
}

数据正在从 BusinessAddressViewModel 传递到 BusinessAddressRowViewModel。BusinessAddressView 包含创建所有行的列表。

class BusinessAddressViewModel: ObservableObject {
    var businessAddressRepository: BusinessAddressRepository

    // Published Properties
    @Published var businessAddressRowViewModels = [BusinessAddressRowViewModel]()
    
    // Combine Cancellable
    private var cancellables = Set<AnyCancellable>()
        
    // Intitalizer
    init(businessAddressRepository: BusinessAddressRepository) {
        self.businessAddressRepository = businessAddressRepository
        self.startCombine()
    }
    
    // Starting Combine - Filter results for business addresses created by the current user only.
    func startCombine() {
        businessAddressRepository
            .$businessAddresses
            .receive(on: RunLoop.main)
            .map { businessAddress in
                businessAddress
                    .map { businessAddress in
                        BusinessAddressRowViewModel(businessAddress: businessAddress)
                    }
            }
            .assign(to: \.businessAddressRowViewModels, on: self)
            .store(in: &cancellables)
    }
}

标签: swiftuimapkit

解决方案


你这里有一个初始化问题,与 Map() 无关。您正在尝试在初始化程序中使用businessCoordinates实例化ObservedObject变量,并且我确信会出现Cannot use instance member 'businessCoordinates' within property initializer; property initializers run before 'self' is available错误。

如果您在视图中的任何地方都不需要“businessCoordinates”,除了数据,我会推荐这个:

class BusinessCoordinates: ObservableObject {
    
    public static let shared = BusinessCoordinates()
...
}

这会给你一个Singleton你可以随意使用的。然后你像这样使用它:

struct BusinessMapView: View {
    @State private var region: MKCoordinateRegion

    init() {
        let mapCoordinates = CLLocationCoordinate2D(latitude: BusinessCoordinates.shared.latitude, longitude: BusinessCoordinates.shared.longitude)
        var mapZoomLevel = MKCoordinateSpan(latitudeDelta: 5.00, longitudeDelta: 5.00)
        _region = State(initialValue: MKCoordinateRegion(center: mapCoordinates, span: mapZoomLevel))

    }
            
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

推荐阅读