简体   繁体   English

SwiftUI/ MapKit - 从 MongoDB Realm/ Atlas 集合填充一个 MapAnnotation 结构

[英]SwiftUI/ MapKit - Populate a MapAnnotation Struct from MongoDB Realm/ Atlas collection

I am new to SwiftUI and Realm (using flexible sync), please excuse if it sounds like an elementary question I have location data saved in a MongoDB Atlas collection - Centre我是 SwiftUI 和 Realm(使用灵活同步)的新手,如果这听起来像是一个基本问题,请原谅我将位置数据保存在 MongoDB 地图集 - 中心

class Centre: Object, ObjectKeyIdentifiable {
    @Persisted var _id: ObjectId = ObjectId.generate()
    @Persisted var centreName = ""
    @Persisted var centreDesc = ""
    @Persisted var centreLocation: Coordinates?
    
    override static func primaryKey() -> String? {
          return "_id"
      }
    convenience init(centreName: String, centreDesc: String, centreLocation: Coordinates) {
         self.init()
         self.centreName = centreName
         self.centreDesc = centreDesc
         self.centreLocation = centreLocation
     }
}

and Coordinates are embedded objects where "x" is longitude and "y" is latitude坐标是嵌入对象,其中“x”是经度,“y”是纬度

class Coordinates: EmbeddedObject, ObjectKeyIdentifiable {
    @Persisted var x: Double?
    @Persisted var y: Double?
}

I have created a Struct to conform to the requirements of MapAnnotation protocol as -我创建了一个 Struct 以符合 MapAnnotation 协议的要求,因为 -

struct CustomAnnots: Identifiable {
    let id: UUID
    var nameCentreLoc: String
    var descCentreLoc: String
    let latitude: Double
    let longitude: Double
    var coordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
        }
    }

I am trying to populate this struct from the data from Atlas collection My LocationView - not working我正在尝试从 Atlas 集合中的数据填充此结构我的 LocationView - 不工作

import SwiftUI
import MapKit
import RealmSwift

struct LocationView: View {
    @Environment(\.realm) var realm
    @ObservedResults(Centre.self) var centres
    @ObservedRealmObject var centre: Centre
    @State private var nameCentreLoc = ""
    @State private var descCentreLoc = ""
    @State private var latitude = 0.0
    @State private var longitude = 0.0
    @State private var annots = []
    
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 24.681_858, longitude: 81.811_623),
        span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10)
    )
    var body: some View {

        Map(coordinateRegion: $region, annotationItems: annots, annotationContent: { locations in
            MapPin(coordinate: locations.coordinate)
         })
        .onAppear {
            setSubscription()
           initData()
        }
       
        }
    
    
    private func setSubscription() {
        let subscriptions = realm.subscriptions
        subscriptions.write {
            if let currentSubscription = subscriptions.first(named: "all_centres") {
                currentSubscription.update(toType: Centre.self) { centre in
                    centre.centreName != ""
                }

            } else {
                subscriptions.append(QuerySubscription<Centre>(name: "all_centres") { centre in
                    centre.centreName != ""
                })
            }
        }
    }
    private func initData() {
        nameCentreLoc = centre.centreName
        descCentreLoc = centre.centreDesc
        latitude = (centre.centreLocation?.y)!
        longitude = (centre.centreLocation?.x)!
        let annots = [for centre in centres {
            CustomAnnots(id: UUID(), nameCentreLoc: nameCentreLoc, descCentreLoc: descCentreLoc, latitude: latitude, longitude: longitude)
        }]
    }
}

How do I populate the Struct with data from Centre collection?如何使用中心集合中的数据填充结构?

Changed to (with no errors in Xcode)-更改为(Xcode 中没有错误)-

    var body: some View {
        let annots = [CustomAnnots(id: UUID(), nameCentreLoc: centre.centreName, descCentreLoc: centre.centreDesc, latitude: (centre.centreLocation?.y)!, longitude: (centre.centreLocation?.x)!)]
        Map(coordinateRegion: $region, annotationItems: annots, annotationContent: { locations in
            MapPin(coordinate: locations.coordinate)
         })
        .onAppear {
            setSubscription()
        }
       
        }

now getting runtime error "Force unwrapping nil value"现在收到运行时错误“强制解包 nil 值”

with this function I am able to print out the results to console有了这个 function 我可以打印出结果到控制台

   func getLoc() {
        for centre in centres {
            var annots = [CustomAnnots.init(id: UUID(), nameCentreLoc: centre.centreName, descCentreLoc: centre.centreDesc, latitude: (centre.centreLocation?.y)!, longitude: (centre.centreLocation?.x)!)]
            print(annots)
        }
    }

I get this printed out - [ACCv5.CustomAnnots(id: 67E9DADA-0BCC-4D30-8136-8B666881E82D, nameCentreLoc: "HO", descCentreLoc: "Head Office Artemis Cardiac Care Gurgaon", latitude: 28.438694893842058, longitude: 77.10845294294181)] [ACCv5.CustomAnnots(id: 26DC0C63-5A17-49C7-B4BF-FD3AA1ABF65E, nameCentreLoc: "Panipat", descCentreLoc: "Artemis Heart Centre at Ravindra Hospital", latitude: 29.388306713854682, longitude: 76.95889693063663)] [ACCv5.CustomAnnots(id: D3A70E58-6B65-4F5D-A398-3394B7FB04DF, nameCentreLoc: "Ranchi", descCentreLoc: "Artemis Heart Centre at Raj Hospital", latitude: 23.35731237118492, longitude: 85.32288933068195)]我打印出来了 - [ACCv5.CustomAnnots(id: 67E9DADA-0BCC-4D30-8136-8B666881E82D, nameCentreLoc: "HO", descCentreLoc: "Head Office Artemis Cardiac Care Gurgaon", latitude: 28.438694893842058, longitude: 77.1084512814]294 [ ACCv5.CustomAnnots(id:26DC0C63-5A17-49C7-B4BF-FD3AA1ABF65E,nameCentreLoc:“Panipat”,descCentreLoc:“拉文德拉医院的阿耳忒弥斯心脏中心”,纬度:29.388306713854682,经度:76.95889693063663)] -6B65-4F5D-A398-3394B7FB04DF, nameCentreLoc: "Ranchi", descCentreLoc: "Artemis Heart Center at Raj Hospital", latitude: 23.35731237118492, longitude: 85.32288933068195)]

But I am unable to display MapAnnotations with this -但是我无法用这个显示 MapAnnotations -

    @Environment(\.realm) var realm
    @ObservedResults(Centre.self) var centres
    @State public var annots: [CustomAnnots]
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 24.681_858, longitude: 81.811_623),
        span: MKCoordinateSpan(latitudeDelta: 10, longitudeDelta: 10)
    )
    var body: some View {
        ForEach (centres) { centre in
            var annots = [CustomAnnots.init(id: UUID(), nameCentreLoc: centre.centreName, descCentreLoc: centre.centreDesc, latitude: (centre.centreLocation?.y)!, longitude: (centre.centreLocation?.x)!)]
        }
       // Text("\(annots.count)")
        Map(coordinateRegion: $region, annotationItems: annots, annotationContent: { locations in
            MapMarker(coordinate: locations.coordinate)
         })

Final code after Jay's suggestions Jay 建议后的最终代码

class Centre: Object, ObjectKeyIdentifiable {
    @Persisted var _id: ObjectId = ObjectId.generate()
    @Persisted var centreName = ""
    @Persisted var centreDesc = ""
    @Persisted var centreLocation: Coordinates?
    
    override static func primaryKey() -> String? {
          return "_id"
      }
  
    convenience init(centreName: String, centreDesc: String, x: Double, y: Double) {
         self.init()
         self.centreName = centreName
         self.centreDesc = centreDesc
         self.centreLocation?.x = x
         self.centreLocation?.y = y
     }
    var coordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(latitude: (centreLocation?.y)!, longitude: (centreLocation?.x)!)
        }
}


 Map(coordinateRegion: $region, annotationItems: centres, annotationContent: { centre in
            MapMarker(coordinate: centre.coordinate)
         })

Simplifying may produce a more streamlined solution.简化可能会产生更精简的解决方案。

If the objective is to populate a map from Realm objects, then I think you're on the right track but there are too many moving parts - lets reduce that code.如果目标是从 Realm 对象填充 map,那么我认为您走在正确的轨道上,但是移动部件太多了 - 让我们减少代码。 Let me know if I misunderstood the question..如果我误解了这个问题,请告诉我..

Here's some pseudo code:这是一些伪代码:

Start with the Realm object that contains the data.从包含数据的 Realm object 开始。 Note we don't need the primary key because we are using ObjectId's for that.请注意,我们不需要主键,因为我们为此使用了 ObjectId。 This object has everything needed to track the pin on the map, it can be observed for changes and returns a calculated var containing the MapAnnotation to be used on the map itself, based on the data in the object这个 object 具有跟踪 map 上的引脚所需的一切,它可以观察变化并返回一个计算的变量,其中包含要在 map 本身上使用的 MapAnnotation,基于 object 中的数据

class Centre: Object, ObjectKeyIdentifiable {
    @Persisted var _id: ObjectId = ObjectId.generate()
    @Persisted var centreName = ""
    @Persisted var centreDesc = ""
    @Persisted var x: Double!
    @Persisted var y: Double!

    var mapAnno: MapAnnotation {
        //build the map annotation from the above properties
        return //return the map annotation
    }

    convenience init(centreName: String, centreDesc: String, x: Double, y: Double) {
        self.init()
        self.centreName = centreName
        self.centreDesc = centreDesc
        self.x = x
        self.y = y
     }
}

Then in the view - load up all of the centers and iterate over them retreiving the MapAnnotation from each然后在视图中 - 加载所有中心并迭代它们,从每个中心检索 MapAnnotation

@ObservedResults(Centre.self) var centres //loads all of the centrs

var body: some View {
        ForEach (centres) { centre in
             let mapAnnotation = centre.mapAnno
             //add the annotation to the map

Note this pattern is pretty common as well请注意,这种模式也很常见

Map(coordinateRegion: $region,
    showsUserLocation: true,
    annotationItems: centres) { center in
                    MapAnnotation(coordinate: //get coords from centre)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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