访问和操作 EnvironmentObject 中的数组项

Posted

技术标签:

【中文标题】访问和操作 EnvironmentObject 中的数组项【英文标题】:Accessing and manipulating array item in an EnvironmentObject 【发布时间】:2021-01-10 12:26:06 【问题描述】:

我有一个 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,而不仅仅是我传递给视图的变量。

任何帮助将不胜感激。

编辑:添加活动类型

【问题讨论】:

Activity 是什么类型? 离题,但属性名称应以小写字母开头。 刚刚编辑添加活动。 您需要对已发布数组的元素使用绑定(因为元素是值,所以如果直接传递则复制)。请参阅***.com/a/59001742/12299030 中的场景示例。 谢谢,我现在去看看! 【参考方案1】:

此方法与本教程中的 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])) 
              ...
          
          ...
      
  

ActivityDetail 中使用@Binding 包装器。


    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, Identifiable, 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)")
    


【讨论】:

以上是关于访问和操作 EnvironmentObject 中的数组项的主要内容,如果未能解决你的问题,请参考以下文章

呈现工作表时 EnvironmentObject 不起作用

如何使用@EnvironmentObject 在 SwiftUI 中自动填充和更新列表?

ObjectBinding 和 EnvironmentObject 有啥区别?

如何从类而不是视图更改@EnvironmentObject

SwiftUI中如何使用@EnvironmentObject在AppDelegate和SceneDelegate/Views之间共享数据

对 SwiftUI 中的 @EnvironmentObject 感到困惑