访问和操作 EnvironmentObject

问题描述

我有一个 EnvironmentObject 用于生成列表

class Activityviewmodel: ObservableObject {
    @Published var Activities = [Activity]()
    
    init() {
        self.Activities = ActivityService.fetchActivities()
    }
}

struct Activity: Codable {
    var Id: UUID
    var Name: String
    var Records: [Record]
    
    init(Name:String) {
        self.Id = UUID.init()
        self.Name = Name
        self.Records = [Record]()
    }
}

当我在视图中使用它时,我可以使用 ForEach 来访问 Activities 数组中的每个值。

我的问题是当我使用 NavigationLink 将这个 Activity 传递给另一个视图时,它没有使用 EnvironmentObject

我的“父视图”代码

ForEach(0..<activities.Activities.count,id: \.self) { activity in
    HStack {
        ActivityListItemView(activity: self.activities.Activities[activity])
    }
}

我的孩子查看代码

struct ActivityListItemView: View {
    let activity: Activity
    
    var body: some View {
        NavigationLink(destination: ActivityDetail(Activity: activity)) {
            HStack {
                vstack {
                    HStack {
                        Text(activity.Name)
                        Text("\(activity.Records.count) records")
                    }
                }
                
                Text(">")
            }
        }
        .buttonStyle(PlainButtonStyle())
    }
}

如果我随后更新 viewmodel,我需要将其复制到子视图中。但我不知道如何让它使用 EnvironmentObject,而不仅仅是我传递给视图的变量。

任何帮助将不胜感激。

编辑:添加活动类型

解决方法

这种方法类似于本教程中的 Apple 方法。

https://developer.apple.com/tutorials/swiftui/handling-user-input


确认Identifiable Equatable


   struct Activity: Codable,Identifiable,Equatable {
       var id: UUID
       var name: String
   //    var Records: [Record]
       
       init(Name:String) {
           self.id = UUID()
           self.name = Name
   //        self.Records = [Record]()
       }
   }

迭代 activity.activities 并将您的 view-modelactivity 传递给 ActivityListItemView

   ForEach(viewModel.activities) { activity in
     HStack {
         ActivityListItemView(viewModel: viewModel,activity: activity)
     }
 }

ActivityListItemView中,找到其活动的索引

private var activityIndex: Int? {
     viewModel.activities.firstIndex(of: activity)
  }

打开 activityIndex 并将 $viewModel.activities[index] 传递给 ActivityDetail

var body: some View {
      if let index = activityIndex {
          NavigationLink(destination: ActivityDetail(activity: $viewModel.activities[index])) {
              ...
          }
          ...
      }
  }

@Binding 中使用 ActivityDetail 包装器。


    struct ActivityDetail: View {
        @Binding var activity: Activity
        
        var body: some View {
            ...
        }
    }

一个完整的工作示例。

class ActivityViewModel: ObservableObject {
    @Published var activities = [Activity]()
    
    init() {
        self.activities = [Activity(Name: "A"),Activity(Name: "B"),Activity(Name: "C"),Activity(Name: "D"),Activity(Name: "E")]
    }
}

struct Activity: Codable,Equatable {
    var id: UUID
    var name: String
//    var Records: [Record]
    
    init(Name:String) {
        self.id = UUID()
        self.name = Name
//        self.Records = [Record]()
    }
}


struct ActivityView: View {
   @ObservedObject  var viewModel = ActivityViewModel()
    var body: some View {
        Button(action: {
            self.viewModel.activities.append(Activity(Name: "\(Date())"))
        },label: {
            Text("Button")
        })
        ForEach(viewModel.activities) { activity in
            HStack {
                ActivityListItemView(viewModel: viewModel,activity: activity)
            }
        }

    }
}


struct ActivityListItemView: View {
    
    @ObservedObject var viewModel: ActivityViewModel
    
    let activity: Activity
    
    private var activityIndex: Int? {
        viewModel.activities.firstIndex(of: activity)
    }
    
    var body: some View {
        if let index = activityIndex {
            NavigationLink(destination: ActivityDetail(activity: $viewModel.activities[index])) {
                HStack {
                    VStack {
                        HStack {
                            Text(activity.name)
    //                        Text("\(activity.Records.count) records")
                        }
                    }
                    Text(">")
                }
            }
            .buttonStyle(PlainButtonStyle())
        }
    }
}


struct ActivityDetail: View {
    @Binding var activity: Activity
    
    var body: some View {
        Text("\(activity.name)")
    }
}