如何在 SwiftUI 中使用可观察对象并与 NavigationLink 绑定?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中使用可观察对象并与 NavigationLink 绑定?【英文标题】:How do I use Observable Object and Binding with the NavigationLink in SwiftUI? 【发布时间】:2021-03-21 09:18:41 【问题描述】:

我是 Swift 和 SwiftUI 的新手,我正在练习使用属性包装器。我创建了一个简单的应用程序,您可以在其中单击伦敦、纽约或迈阿密。一旦您点击其中任何一个,它将导航到它自己的屏幕,该屏幕将显示城市名称、当前时间和 covid 死亡人数。

我没有将它连接到我只是想练习的 API。我花了将近 8 个小时试图找到一种方法,让城市在第二个视图中显示自己的属性,而无需创建 3 个单独的视图模型。每个导航目的地显示伦敦的属性。我正在尝试找到一种方法来解决它。我还从可识别模型中创建了 3 个对象/实例。如果你能帮助我,非常感谢。

这是我的视图模型:

class CityViewModel: ObservableObject 


@Published var title = "London"
@Published var deaths = "5894"
@Published var time = "8:36"


现在这是我的内容视图:

struct ContentView: View 
@ObservedObject var cities = CityViewModel()


    
var body: some View 
    NavigationView 
        ZStack 
            Color.black
                .ignoresSafeArea()
        
        VStack 
            
            NavigationLink(
                destination: ToogleView(cityname: self.$cities.title, deaths: self.$cities.deaths, time: self.$cities.time),
                label: 
                    Text("London")
                        .foregroundColor(.white)
                        .bold()
                        .font(.system(size: 30))
                   
                )
            Spacer()
            NavigationLink(
                destination: ToogleView(cityname: self.$cities.title, deaths: self.$cities.deaths, time: self.$cities.time),
                label: 
                    Text("New York")
                        .foregroundColor(.white)
                        .bold()
                        .font(.system(size: 30))
                )

我为单击 Navigationlink 时创建了第二个视图

struct ToogleView: View 

@Binding var cityname:String
@Binding var deaths:String
@Binding var time:String




var body: some View 
    ZStack 
        Color.black
            .ignoresSafeArea()
        VStack 
            Spacer()
            Text(cityname)
                .foregroundColor(.white)
                .font(.system(size: 24))
                .bold()
            Spacer()
            Text(time)
                .foregroundColor(.white)
                .font(.system(size: 18))
            Spacer()
            HStack
                Image(systemName: "person.3.fill")
                    .foregroundColor(.white)
                Text(deaths)
                    .foregroundColor(.red)
                    .bold()
                
                
                    
                    
            
        Spacer()
        
    
  

【问题讨论】:

【参考方案1】:

好吧,您将需要在某个地方存储数据,因为您不想使用 api 并避免使用不同的视图模型,这是一种选择。

创建一个名为 City 的 swift 文件并添加:

  struct City: Identifiable 
    let id = UUID()
    let name: String
    let deaths: Int
    let time: String

然后在CityViewModel中创建实例

    let myChosenCities = [City(name: "London", deaths: 3252, time: "8:32"),
                      City(name: "Japan", deaths: 3461, time: "4:21"),
                      City(name: "Canada", deaths: 2352, time: "9:93")
]

然后修改你的视图以接受一个像这样初始化的城市。

  struct ToogleView: View 

    let city: City

var body: some View 
    ZStack 
        Color.black
            .ignoresSafeArea()
        VStack 
            Spacer()
            Text(city.name)
                .foregroundColor(.white)
                .font(.system(size: 24))
                .bold()
            Spacer()
            Text(city.time)
                .foregroundColor(.white)
                .font(.system(size: 18))
            Spacer()
            HStack
                Image(systemName: "person.3.fill")
                    .foregroundColor(.white)
                Text(String(city.deaths))
                    .foregroundColor(.red)
                    .bold()
            
        Spacer()
        
    
  

然后将您的父视图更改为:

struct ContentView: View 
    @ObservedObject var vm = CityViewModel()
    
    var body: some View 
        NavigationView 
            ZStack 
                Color.black
                    .ignoresSafeArea()
                
                VStack 
                    List(vm.myChosenCities)  city in
                        NavigationLink(destination: ToogleView(city: city)) 
                        HStack 
                            VStack 
                                Text(city.name)
                                Text(city.time)
                            
                            Text(String(city.deaths))
                        
                        
                    
                
            
        
    

你的 viewModel 是这样的:

    class CityViewModel: ObservableObject 

    
    let myChosenCities = [City(name: "London", deaths: 3252, time: "8:32"),
                          City(name: "Japan", deaths: 3461, time: "4:21"),
                          City(name: "Canada", deaths: 2352, time: "9:93")
    ]


我将您的示例列在一个列表中以便于组织,但您应该能够看到它是如何工作的

【讨论】:

非常感谢!!! :) 我现在也有了更好的理解。 @ObservedObject 仅应在对象的所有者不是视图本身时使用。在此示例中,您应该使用 @StateObject 代替,当视图是 ObservableObject 对象的实际所有者时应该使用它【参考方案2】:

因为您在 ViewModel 中硬编码了伦敦的属性,所以它到处都显示了伦敦的属性。

我建议创建一个城市模型并将您想要显示的 CityModel 传递到 ToggleView

以下示例也是非常静态的,如果您想使用城市的动态数据,则需要对其进行调整

class CityViewModel: ObservableObject 
    @Published var city: [CityModel] = [
        CityModel(title: "London", deaths: 5894, time: "8:36"),
        CityModel(title: "New York", deaths: 2332, time: "3:36")
    ]


struct CityModel 
    var title: String
    var deaths: Int
    var time: String

内容视图

struct ContentView: View 
    @ObservedObject var cities = CityViewModel()

    var body: some View 
        NavigationView 
            ZStack 
                Color.black
                    .ignoresSafeArea()

                VStack 

                    NavigationLink(
                        destination: ToogleView(city: cities.city.first!),
                        label: 
                            Text("London")
                                .foregroundColor(.white)
                                .bold()
                                .font(.system(size: 30))

                        )
                    Spacer()
                    NavigationLink(
                        destination: ToogleView(city: cities.city.last!),
                        label: 
                            Text("New York")
                                .foregroundColor(.white)
                                .bold()
                                .font(.system(size: 30))
                        )
                
            
        
    

切换视图

struct ToogleView: View 
    var city: CityModel

    var body: some View 
        ZStack 
            Color.black
                .ignoresSafeArea()
            VStack 
                Spacer()
                Text(city.title)
                    .foregroundColor(.white)
                    .font(.system(size: 24))
                    .bold()
                Spacer()
                Text(city.time)
                    .foregroundColor(.white)
                    .font(.system(size: 18))
                Spacer()
                HStack
                    Image(systemName: "person.3.fill")
                        .foregroundColor(.white)
                    Text(String(city.deaths))
                        .foregroundColor(.red)
                        .bold()
                
                Spacer()
            
        
    

【讨论】:

感谢沃尔克 :)

以上是关于如何在 SwiftUI 中使用可观察对象并与 NavigationLink 绑定?的主要内容,如果未能解决你的问题,请参考以下文章

如何将可观察对象发布的整数变量绑定到 SwiftUI 中的 textField?

声明后不可访问的可观察对象中的变量(SwiftUI)

SwiftUI 可观察对象返回陈旧数据

SwiftUI-> 线程 1:致命错误:未找到 MyObject.Type 类型的可观察对象(工作表中的 EnvironmentObject)

SwiftUI - 从 Swift 类启动的可观察对象不会更新 ContentView() 上的 @ObservedObject

Combine + SwiftUI 中的最佳数据绑定实践?