SwiftUI中EnvironmentObject的使用(多界面共享数据)

SwiftUI@EnvironmentObject是一个强大的工具,它允许你在多个视图之间共享数据(使用一个可观察对象)。当你有一个复杂的视图层次结构,并且需要在没有直接连接的视图之间共享相同的可观察对象时,它特别有用。

我们之前传递数据主要是通过init方法一层一层的传递,一层两层还行,要是再多了,代码很难维护,逻辑也比较复杂,这可能需要大量的工作,而且有的中间层根本用不到这个传递的数据。

使用EnvironmentObject允许将一个对象(一个可观察对象的实例)附加到父视图。父视图的任何后代(比如push出来的所有视图等)现在都可以访问该对象。

要使用环境对象,首先需要创建一个符合ObservableObject协议的ObservableObject类,这个类将保存我们希望在视图之间共享的数据。

class GameSettings: ObservableObject {
   @Published var score = 0
}

在主界面创建ObservableObject实例,并且设置要共享的数据。

struct EnvironmentObjectDemo: View {
  @StateObject var settings = GameSettings()

    var body: some View {
      NavigationView {
        VStack(spacing: 30) {

          Text("\(settings.score)")
            .font(.title)

          Button("Increase Score") {
            settings.score += 1
          }

          NavigationLink {
            DetailView()
          } label: {
            Text("Show Detail View")
          }
        }
        .frame(height: 200)
      }
      .environmentObject(settings)
   }
}

该界面首先要创建一个ObservableObject实例:

@StateObject var settings = GameSettings()

然后在视图上添加.environmentObject修饰符,并传入要共享的数据:

.environmentObject(settings)

界面中点击“Increase Score”按钮修改score,点击“Show Detail View”按钮跳转到下一个DetailView界面。

struct DetailView: View {
  var body: some View {
    NavigationLink {
      ScoreView()
    } label: {
      Text("Show Score View")
        .font(.title)
    }
  }
}

DetailView界面,没有用到score,而是点击"Show Score View"按钮继续跳转到下一个ScoreView界面,并在这个界面显示score

struct ScoreView: View {
  @EnvironmentObject var settings: GameSettings

  var body: some View {
    Text("Score: \(settings.score)")
  }
}

ScoreView界面中,通过@EnvironmentObject包装器访问共享数据:

@EnvironmentObject var settings: GameSettings

最终效果如下:
在这里插入图片描述
几点总结:

  1. 就像@StateObject@ObservedObject一样,与@EnvironmentObject一起使用的所有类都必须遵守ObservableObject协议。
  2. 我们将settings放入导航堆栈的环境中,这意味着导航堆栈中的所有视图都可以读取该对象,以及导航堆栈显示的任何视图。
  3. 当使用@EnvironmentObject属性包装器时,只要声明期望接收的对象的类型,而不是创建它,我们希望从环境中接收它。
  4. 因为显示的ScoreView在导航堆栈中,它访问相同的环境,这意味着它可以读取我们创建的GameSettings实例对象。
  5. 我们不需要显式地将环境中的GameSettings实例与ScoreView中的settings属性关联起来——SwiftUI会自动计算出它在环境中有一个GameSettings实例,并使用这个实例。即使创建时的变量名和使用的时候定义的变量名不同也没关系。

如果需要向环境中添加多个对象,则应该添加多个.environmentObject修饰符,一个一个的添加即可。

struct EnvironmentObjectDemo: View {
  @StateObject var gameSettings = GameSettings()
  @StateObject var videoSettings = VideoSettings()

    var body: some View {
      NavigationView {
        ......
      }
      .environmentObject(gameSettings)
      .environmentObject(videoSettings)
   }
}

另外如果创建了两个同类型的ObservableObject对象,并且依次添加到环境中去,那么最早添加的那个起作用,后添加的无效。
在这里插入图片描述
上面代码创建了2个GameSettings的实例对象,并通过.environmentObject修饰符向下传递。代码中改变了gameSettings2score值,但是最后到ScoreView界面还是显示的gameSettings1传递的score值。

最后,希望能够帮助到有需要的朋友,如果您觉得有帮助,还望点个赞,添加个关注,笔者也会不断地努力,写出更多更好用的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值