SwiftUI通过引用将类对象传递给另一个视图

时间:2020-08-24 20:34:39

标签: ios swiftui pass-by-reference observedobject environmentobject

我正在尝试学习SwiftUI,并且将开发一个带有标签视图的简单应用,并在这些视图之间共享核心运动数据。

主要思想是创建运动管理器对象(如here),并在所有视图中使用传感器值。

ContentView.swift

import SwiftUI

struct ContentView: View {

@State private var selection = 1

@State private var viewNames : [String] = ["View1", "View2"]

var body: some View {
    
    TabView(selection: $selection){
        
        View1(viewName: $viewNames[0]).tag(0)
        
        View2(viewName: $viewNames[1]).tag(1)
                    
        }
    }
}

View1.swift

import SwiftUI

struct View1 : View {

@Binding var viewName : String

var body: some View {
    
    Text("First View")
    .font(.title)
    .foregroundColor(Color.gray)
    .tabItem {
        VStack {
            Image(systemName: "star")
            Text(viewName)
        }
     }
  }
}

View2.swift

struct View2 : View {

@Binding var viewName : String


var body: some View {
    
    VStack {
        Text("Second View")
            .font(.title)
            .foregroundColor(Color.green)
            .padding(.top)
        
        View21(motionManager: MotionManager())

        
        
    }.tabItem {
        VStack {
            Image(systemName:"heart")
            Text(viewName)
        }
    }
    
  }

}

View21.swift

struct View21 : View {

@ObservedObject var motionManager : MotionManager

@State private var showDetails = false


var body: some View{
  Text(String(format: "%.2f", motionManager.x))
}

使用这些代码,我可以在View21中使用传感器数据,但是无法在以上层次结构的视图中访问数据。

此外,我在ContentView中创建了@ObservedObject(例如here),并将其传递给所有视图。我的应用程序可以在模拟器中运行,但不能在实际设备上运行。 我可以看到传感器数据正在更改,但是无法切换选项卡视图。 我尝试使用@EnvironementObject代替@ObservedObject,但是行为是相同的。

非常感谢您为我的问题提供的帮助和建议。 祝福

1 个答案:

答案 0 :(得分:1)

好的,Paulw11是对的,您可能想将ObservableObject注入到环境中,然后在每个要访问该实例的视图中,只需使用@EnvironmentObject属性包装器添加一个属性。下面,我汇总了我能想到的最简单的示例,以便您可以了解其工作原理。

import SwiftUI
import Combine

class ManagerPlaceholder: ObservableObject {
    
    @Published var propertyOne: Double = 1.0
    @Published var propertyTwo: Double = 2.0
    
    func action() {
        propertyOne = Double.random(in: 0.0..<100.00)
        propertyTwo = Double.random(in: 0.0..<100.00)
    }
    
}


struct ContentView: View {
    
    @EnvironmentObject var manager: ManagerPlaceholder
    
    var body: some View {
        TabView {
            Subview()
                .tabItem { Label("First", systemImage: "hexagon.fill") }
                .tag(1)
            Subview()
                .tabItem { Label("Second", systemImage: "circle.fill") }
                .tag(2)
            
        }
    }
    
}

struct Subview: View {
    
    @EnvironmentObject var manager: ManagerPlaceholder
    
    var body: some View {
        VStack {
            Text("Prop One: \(manager.propertyOne)").padding()
            Text("Prop Two: \(manager.propertyTwo)").padding()
            Button("Change", action: manager.action).padding()
        }
    }
    
}

上面是

  • 一个简单的ObservableObject-它所做的就是将两个Double设置为一个随机值(注意,要观察的属性标记为@Published)
  • 选项卡视图
  • 一个简单的子视图

请注意,两个视图都有一个@EnvironmentObject var manager: ManagerPlaceholder。您没有直接设置该属性。该行表示您要引用环境中的ManagerPlaceholder实例。环境是SwiftUI为您管理的一种“存储池”。您可以向其添加对象的实例,然后在需要该对象的子视图中对其进行引用。

因此,为确保在环境中,请在实例化视图(可以是选项卡视图或任何超级视图)时将其添加。因此,例如,在您的_NAME_App.swift(对于iOS 14目标)或SceneDelegate.swift(对于iOS 13目标)中,您可以这样实例化视图:

ContentView().environmentObject(ManagerPlaceholder())

如果您运行上面的代码,则单击“更改”按钮时将看到它随机设置了两个属性,并且当您来回切换时,两个子视图将看到完全相同的值,因为它们都引用相同的值实例。

如有任何不清楚之处,请随时发表评论。