在 SwiftUI 中从 Observable 视图模型初始化 Map

Posted

技术标签:

【中文标题】在 SwiftUI 中从 Observable 视图模型初始化 Map【英文标题】:Initializing Map from an Observable view model in SwiftUI 【发布时间】:2021-04-08 04:25:17 【问题描述】:

我正在尝试在视图模型的 SwiftUI 视图上实现 Map。我在网上找到的每个例子都硬编码一个坐标。就我而言,我正在使用 Codable 结构初始化视图模型,但我不知道坐标是什么。

我在构建项目时没有遇到编译器问题,但是画布崩溃了。我尝试过关闭 Xcode、清理派生数据等,但这似乎并没有解决问题。

非常感谢任何关于我的错误的建议。

class EarthquakeViewModel: ObservableObject 
    @Published private(set) var quakeData: Feature
    @State var region: MKCoordinateRegion
    
    
    init(quakeData: Feature) 
        self.quakeData = quakeData
        let center = CLLocationCoordinate2D(latitude: quakeData.geometry.coordinates[0],
                                        longitude: quakeData.geometry.coordinates[1])
        let span = MKCoordinateSpan(latitudeDelta: 1.0, longitudeDelta: 1.0)
        region = MKCoordinateRegion(center: center,
                                    span: span)
    

        public lazy var title: String = 
        quakeData.properties.title
    ()

这是我的ContentView

struct EarthquakeView: View 
    @ObservedObject var viewModel: EarthquakeViewModel
    
    var body: some View 
        VStack 
            Text(viewModel.title)
//            makeMapView()
            Map(coordinateRegion: $viewModel.region)
        
    

// 这个我也试过了,还是不行。

extension EarthquakeView 
    @ViewBuilder func makeMapView() -> some View 
        Map(coordinateRegion: $viewModel.region)
    


更新

这是来自诊断的消息。关闭 Xcode 清理派生数据似乎无法解决它,所以我认为我的问题在于我的声明之一:

RemoteHumanReadableError: Failed to update preview.

The preview process appears to have crashed.

Error encountered when sending 'render' message to agent.

==================================

|  RemoteHumanReadableError: The operation couldn’t be completed. (BSServiceConnectionErrorDomain error 3.)
|  
|  BSServiceConnectionErrorDomain (3):
|  ==BSErrorCodeDescription: OperationFailed

更新 2

我调整了我的数据模型并从中添加了一个计算区域变量,所以我现在是如何获取该区域的:

extension Feature /* Feature is a Codable struct */ 
    var region: MKCoordinateRegion 
        let center = CLLocationCoordinate2D(latitude: geometry.coordinates[0],
                                            longitude: geometry.coordinates[1])
        let span = MKCoordinateSpan(latitudeDelta: 1.0, longitudeDelta: 1.0)
        let region = MKCoordinateRegion(center: center,
                                        span: span)
        
        return region
    

在jnpdx's 的建议下,我将视图模型上的区域更新为 @Published

class EarthquakeViewModel: ObservableObject 
    `@Published private(set) var quakeData: Feature
    `@Published var region: MKCoordinateRegion
    
    init(quakeData: Feature) 
        self.quakeData = quakeData
        region = quakeData.region
    
    
    public lazy var title: String = 
        quakeData.properties.title
    ()

最后,我的观点如下:

struct EarthquakeView: View 
    @ObservedObject var viewModel: EarthquakeViewModel
    
    @State var region: MKCoordinateRegion
    
    init(viewModel: EarthquakeViewModel) 
        self.viewModel = viewModel
        _region = State(initialValue: viewModel.region)
    
    
    var body: some View 
        VStack 
            Text(viewModel.title)
            Map(coordinateRegion: $region)
        
    

新的错误是这样的。关闭 Xcode、重新启动、清理派生数据等似乎无法解决它,所以我很快得出结论,我缺少一些基本的东西:

PreviewUpdateTimedOutError:更新时间超过 5 秒 来自 CombineQuake.app (16766) 中 EarthquakeView_Previews 的预览 耗时超过 5 秒。

更新 3

预览初始化:

struct EarthquakeView_Previews: PreviewProvider 
    static var previews: some View 
        
        let quakeData = EarthQuakeData(mag: 6.5,
                                       place: "32km W of Sola, Vanuatu",
                                       time: 1388592209000,
                                       updated: 1594407529032,
                                       tz: 660,
                                       url: "https://earthquake.usgs.gov/earthquakes/eventpage/usc000lvb5",
                                       detail: "https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=usc000lvb5&format=geojson",
                                       felt: nil,
                                       cdi: nil,
                                       mmi: nil,
                                       alert: nil,
                                       status: "reviewed",
                                       tsunami: 1,
                                       sig: 650,
                                       net: "us",
                                       code: "c0001vb5",
                                       ids: ",pt14001000,at00myqcls,usc000lvb5,",
                                       sources: "pt,at,us",
                                       types: "cap,geoserve,impact-link,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary",
                                       nst: nil,
                                       dmin: 3.997,
                                       rms: 0.76,
                                       gap: 14.0,
                                       magType: "mww",
                                       type: "earthquake",
                                       title: "M 6.5 - 32km W of Sola, Vanuatu")
        let geometry = Geometry(type: "Point",
                                coordinates: [167.249, -13.8633, 187.0])
        let earthquake = Feature(type: "Feature",
                                 properties: quakeData,
                                 geometry: geometry,
                                 id: "usc000lvb5")
        
        let viewModel = EarthquakeViewModel(quakeData: earthquake)
        
        
        EarthquakeView(viewModel: viewModel)
    

【问题讨论】:

无法在 Xcode 12.4 上重现,尽管我不得不对您的代码进行一些猜测,因为您没有包含 Feature 或预览本身。不过,马上,我注意到您在ObservableObject 中使用了@State——应该是@Published 感谢您的关注。我更新了你的建议。不同的错误,仍然没有地图:( 对我来说仍然无法重现(尽管我仍然不得不推断一些关于代码的事情)。你能展示你是如何创建预览的吗?它是否在非预览情况下的模拟器上工作? 感谢您的关注。我更新了PreviewProvider。如果我注释掉 Map 声明,文本将按预期呈现。 预览代码不可编译,因为您在此处包含的代码中缺少所有类型,但对我来说没有什么太不寻常的地方。仍然有兴趣知道这是否仅发生在预览版或 sim/设备上。 【参考方案1】:

如果您在模拟器而不是预览版上运行它,您会得到一个更有用的错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid Region <center:+167.24900000, -13.86330000 span:+1.00000000, +1.00000000>'

我变了:

let geometry = Geometry(type: "Point",
                                coordinates: [167.249, -13.8633, 187.0])

let geometry = Geometry(type: "Point",
                                coordinates: [45, 34, 187.0])

效果很好。

您的纬度 167.249 超出了 -90 到 90 的范围,这是有效范围。

【讨论】:

哈哈。 USGS 将坐标反向发回。我非常感谢您的帮助。谢谢你。 earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php

以上是关于在 SwiftUI 中从 Observable 视图模型初始化 Map的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中从 UIViewRepresentable 呈现视图

SwiftUI 和具有 @Published 的组合 Observable 对象不断发布

在 SwiftUI 中从数据模型中搜索数组

如何在 SwiftUI 中从 FetchedResults (CoreData) 中获取 NSOrderedSet

如何在 SwiftUI 中从减去的子视图中关闭视图

显示来自 Observable Object SwiftUI 的列表