你能从 SwiftUI 中的 MapKit 数据库中获取纬度和经度吗

Posted

技术标签:

【中文标题】你能从 SwiftUI 中的 MapKit 数据库中获取纬度和经度吗【英文标题】:Can You Get Latitude and Longitude From A Database for MapKit in SwiftUI 【发布时间】:2021-10-08 06:23:49 【问题描述】:

我正在处理一个 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)
    

【问题讨论】:

第二块上面的代码无法编译。它抛出一个错误。由于 region 引用了 businessCoordinates,所以这是不允许的。我的问题是如何将区域与数据库中的数据一起使用,因为您无法引用其他属性,例如 businessCoordinates。 【参考方案1】:

这里有一个初始化问题,与 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)
    

【讨论】:

虽然我喜欢这种方法,但我不确定它是否适用于我的应用程序。我已经更新了上面的问题以显示当前的 BusinessCoordinates 文件。由于该文件是行视图的视图模型,因此我正在为 VM 提供业务地址。这意味着我必须使用公司地址启动共享财产。我不知道这怎么可能。 您将其放入BusinessAddressRowViewModel,但在MapView 中您使用BusinessCoordinates 作为ObservedObject。这是哪里来的? 我很抱歉造成混乱。我在原始帖子中重命名了文件,尝试简化事情。我已更改 ObservedObject 的命名以匹配文件名。 数据从何而来?离开你的地图视图,你如何将数据输入BusinessAddressRowViewModel?在您实例化 BusinessAddressRowViewModel 之前,是什么保存了这些数据? 我添加了从 Firebase Firestore 中提取数据的存储库文件和创建 BusinessAddressRowViewModels 的 BusinessAddressViewModel。

以上是关于你能从 SwiftUI 中的 MapKit 数据库中获取纬度和经度吗的主要内容,如果未能解决你的问题,请参考以下文章

Swift:SwiftUI中MapKit的使用体验

SwiftUI:如何在 MapKit 中自定义地理区域的位置?

使用 SwiftUI 和 MapKit 检索用户当前位置

在 swiftUI 2 中向 MapKit 添加 MapMarker

如何在 SwiftUI MapKit 的 updateUIView 中添加“.setRegion”?

使用 SwiftUI 将单个引脚添加到 Mapkit