@EnvironmentObject 通过 navigationLink 不能很好地工作

fra*_*003 7 swiftui swiftui-navigationlink

我用我@EnvironmentObject的让我的 TeamData 可以被不同的人使用,但它不能很好地工作。当我通过列表中的导航链接转到另一个视图时,这很好。当我点击同一个视图的按钮时,它崩溃了..
我想我放错了什么。有人可以帮助解决这个问题吗?这是否意味着我需要先@EnvironmentObject在 NavigationView添加才能使用它?谢谢

演示:https : //youtu.be/-iRadrHd94c

import SwiftUI

struct GameRecordListView: View {
@EnvironmentObject var teamResult : TeamResult

@State var hint : String = ""
@State var successRegistration : Bool = false
@State var sheetPresented: Bool = false
var body: some View {
     VStack{

        List(0 ..< 12){ item in
            NavigationLink(destination: GameDetailRecordView()){   <-this works well
                Text("444")

            }
        }
        VStack{
            Spacer()
            HStack{
                Spacer()
                NavigationLink(destination: GameDetailRecordView())  <-this doesn't works well and crashed
                {
                    Image(systemName: "pencil.circle")
                        .resizable()
                        .frame(width: 35, height: 35)
                        .padding(12)
                        .background(Color.blue)
                        .foregroundColor(Color.white)
                        .clipShape(Circle())

                }
            }.padding(15)

        }

     }.onAppear(perform: {
        print("teamResult:\(self.teamResult.groupID):\(self.teamResult.groupName)")
     })
}
}
Run Code Online (Sandbox Code Playgroud)

我在这个视图中创建了一个 environmentObject

import SwiftUI
import SwiftyJSON

struct TeamDetail: View {
@EnvironmentObject var teamResult : TeamResult
//    @ObservedObject var teamResult: TeamResult
var roles = ["GameRecord", "Schedule", "Money", "Member"]
@State var show = false
@State private var selectedIndex = 0
var body: some View {
    ZStack{
        VStack {
            Picker(selection: $selectedIndex, label: Text("")) {
                ForEach(0..<roles.count) { (index) in
                    Text(self.roles[index])
                }
            }
            .pickerStyle(SegmentedPickerStyle())

            HStack{
                containedView()

            }
            Spacer()

            }


        }.navigationBarTitle(teamResult.groupName)
        .onAppear(perform:{

        })
}



//select different view by selectedIndex
func containedView() -> AnyView {
   switch selectedIndex {
   case 0:
       return AnyView(
            GameRecordListView().environmentObject(teamResult)   <-create environmentObject here
       )

   case 1:

      return AnyView(Text("")
           .padding(30))


   case 2:
      return AnyView(
        BookkeepingView().environmentObject(teamResult)

    )


   default:
    return AnyView(
        TeamMemberListView().environmentObject(teamResult))
}

}
}
Run Code Online (Sandbox Code Playgroud)

我使用@EnviromentObject 的视图

import SwiftUI

struct GameDetailRecordView: View {
  @EnvironmentObject var teamResult : TeamResult
  var body: some View {
     Text("ID:\(teamResult.groupID)Name:\(teamResult.groupName)")
  }
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

import SwiftUI

struct GameRecordListView: View {
@EnvironmentObject var teamResult : TeamResult

@State var hint : String = ""
@State var successRegistration : Bool = false
@State var sheetPresented: Bool = false
var body: some View {
     VStack{

        List(0 ..< 12){ item in
            NavigationLink(destination: GameDetailRecordView()){   <-this works well
                Text("444")

            }
        }
        VStack{
            Spacer()
            HStack{
                Spacer()
                NavigationLink(destination: GameDetailRecordView())  <-this doesn't works well and crashed
                {
                    Image(systemName: "pencil.circle")
                        .resizable()
                        .frame(width: 35, height: 35)
                        .padding(12)
                        .background(Color.blue)
                        .foregroundColor(Color.white)
                        .clipShape(Circle())

                }
            }.padding(15)

        }

     }.onAppear(perform: {
        print("teamResult:\(self.teamResult.groupID):\(self.teamResult.groupName)")
     })
}
}
Run Code Online (Sandbox Code Playgroud)

Ken*_*kin 5

尝试在 NavigationLink 的视图上添加 environmentObject

 NavigationLink(destination: GameDetailRecordView().environmentObject(teamResult))
Run Code Online (Sandbox Code Playgroud)

  • 你好,我用这个方法,可以成功。但我想知道为什么列表中的NavigationLink不需要添加.environmentObject(teamResult)而另一个需要添加.environmentObject(teamResult)。这是否意味着NavigationLink创建了一个新的环境?我认为 GameRecordListView().environmentObject(teamResult) 下面的所有视图都可以使用 @environmentObject teamResult 。 (8认同)
  • 嗨@frank61003,您是否设法弄清楚为什么会发生这种情况?我也有同样的情况。 (5认同)
  • 当“NavigationLink”在运行时动态“创建”时,似乎所有“environmentObjects”都不会被传递。在这些情况下,您必须再次提供环境对象。 (4认同)

Nat*_*ton 5

这是否意味着我需要首先在 NavigationView 添加 @EnvironmentObject 以便我可以使用它?

正确的是,NavigationLink 无法将环境对象传递到其目的地;只有 NavigationView 可以做到这一点,因为它拥有视图层次结构。

所以,如果你在代码中的某个地方做了这样的事情:

NavigationView {
  ContentView()
    .environmentObject(teamResult)
}
Run Code Online (Sandbox Code Playgroud)

您需要将其更改为:

NavigationView {
  ContentView()
}
.environmentObject(teamResult)
Run Code Online (Sandbox Code Playgroud)

然后 ContentView 将能够接收 @EnvironmentObject 以及其中的 NavigationLink 的任何目标视图,而无需environmentObject(_:)在每个目标视图上使用视图修饰符。

  • 这应该是最重要的答案。它准确地解决了如何使环境对象正常工作的问题,就像环境对象应有的那样。如果我想通过所有导航链接显式传递环境对象,我只需将其设置为视图本身的显式 @Binding。 (3认同)