在视图中重新实例化 @EnvironmentObject
Reinstantiate an @EnvironmentObject in a view
在我的应用程序中,我需要在点击按钮时重新实例化 @EnvironmentObject
。哪里才是正确的做法?
这是我的视图的屏幕截图 - 在存档对象列表中,我想要不可变对象。所以,当我点击 Archive Object
时,我想将当前对象添加到数组并创建一个新的当前对象。
该应用程序的简化版本如下所示。
我实例化对象在SceneDelegate
:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var myObject = MyObject()
let myObjects = MyObjects()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
.environmentObject(myObject)
.environmentObject(myObjects)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
//.....
}
这是我的模型:
class MyObject: ObservableObject, Identifiable {
@Published var id = UUID()
}
class MyObjects: ObservableObject {
@Published var values: [MyObject] = [
MyObject(),
MyObject()
]
}
在我看来,我需要将我的当前对象放入一个(存档)数组,然后创建一个新的当前对象来使用。这是我正在尝试的:
struct ContentView: View {
@EnvironmentObject var currentObject: MyObject
@EnvironmentObject var objects: MyObjects
var sceneDelegate: UISceneDelegate {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let sd = windowScene.delegate as? SceneDelegate else { fatalError() }
return sd
}
var body: some View {
VStack {
Form {
Section(header: Text("Current Object")) {
Text(currentObject.id.uuidString)
}
Section(header: Text("Archived Objects")) {
List(objects.values, id: \.id) { object in
Text(object.id.uuidString)
}
Button(action: {
self.objects.values.append(self.currentObject)
// as the environment object is get only, I cannot reinstantiate it here...
// self.currentObject = MyObject()
}) {
Text("Archive Object")
}
}
}
Spacer()
}
}
}
这是一个解决方案。查看内联评论。
测试 Xcode 11.4 / iOS 13.4
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
// Usage
ContentView(current: MyObject())
.environmentObject(MyObjects())
}
}
struct ContentView: View {
@EnvironmentObject var objects: MyObjects
@State private var current: MyObject // tracks current
init(current: MyObject) {
_current = State(initialValue: current)
}
var body: some View {
// rebuilt on *current* changed
ContentInnerView(current: $current)
.environmentObject(current)
}
struct ContentInnerView: View {
@Binding var current: MyObject // change current
@EnvironmentObject var objects: MyObjects
@EnvironmentObject var currentObject: MyObject
init(current: Binding<MyObject>) {
_current = current
}
var sceneDelegate: UISceneDelegate {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let sd = windowScene.delegate as? SceneDelegate else { fatalError() }
return sd
}
var body: some View {
VStack {
Form {
Section(header: Text("Current Object")) {
Text(currentObject.id.uuidString)
}
Section(header: Text("Archived Objects")) {
List(objects.values, id: \.id) { object in
Text(object.id.uuidString)
}
Button(action: {
self.objects.values.append(self.currentObject)
self.current = MyObject() // << works !!
}) {
Text("Archive Object")
}
}
}
Spacer()
}
}
}
}
在我的应用程序中,我需要在点击按钮时重新实例化 @EnvironmentObject
。哪里才是正确的做法?
这是我的视图的屏幕截图 - 在存档对象列表中,我想要不可变对象。所以,当我点击 Archive Object
时,我想将当前对象添加到数组并创建一个新的当前对象。
该应用程序的简化版本如下所示。
我实例化对象在SceneDelegate
:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var myObject = MyObject()
let myObjects = MyObjects()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView()
.environmentObject(myObject)
.environmentObject(myObjects)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
//.....
}
这是我的模型:
class MyObject: ObservableObject, Identifiable {
@Published var id = UUID()
}
class MyObjects: ObservableObject {
@Published var values: [MyObject] = [
MyObject(),
MyObject()
]
}
在我看来,我需要将我的当前对象放入一个(存档)数组,然后创建一个新的当前对象来使用。这是我正在尝试的:
struct ContentView: View {
@EnvironmentObject var currentObject: MyObject
@EnvironmentObject var objects: MyObjects
var sceneDelegate: UISceneDelegate {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let sd = windowScene.delegate as? SceneDelegate else { fatalError() }
return sd
}
var body: some View {
VStack {
Form {
Section(header: Text("Current Object")) {
Text(currentObject.id.uuidString)
}
Section(header: Text("Archived Objects")) {
List(objects.values, id: \.id) { object in
Text(object.id.uuidString)
}
Button(action: {
self.objects.values.append(self.currentObject)
// as the environment object is get only, I cannot reinstantiate it here...
// self.currentObject = MyObject()
}) {
Text("Archive Object")
}
}
}
Spacer()
}
}
}
这是一个解决方案。查看内联评论。
测试 Xcode 11.4 / iOS 13.4
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
// Usage
ContentView(current: MyObject())
.environmentObject(MyObjects())
}
}
struct ContentView: View {
@EnvironmentObject var objects: MyObjects
@State private var current: MyObject // tracks current
init(current: MyObject) {
_current = State(initialValue: current)
}
var body: some View {
// rebuilt on *current* changed
ContentInnerView(current: $current)
.environmentObject(current)
}
struct ContentInnerView: View {
@Binding var current: MyObject // change current
@EnvironmentObject var objects: MyObjects
@EnvironmentObject var currentObject: MyObject
init(current: Binding<MyObject>) {
_current = current
}
var sceneDelegate: UISceneDelegate {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let sd = windowScene.delegate as? SceneDelegate else { fatalError() }
return sd
}
var body: some View {
VStack {
Form {
Section(header: Text("Current Object")) {
Text(currentObject.id.uuidString)
}
Section(header: Text("Archived Objects")) {
List(objects.values, id: \.id) { object in
Text(object.id.uuidString)
}
Button(action: {
self.objects.values.append(self.currentObject)
self.current = MyObject() // << works !!
}) {
Text("Archive Object")
}
}
}
Spacer()
}
}
}
}