SwiftUI 常用 Property Wrappers 之 EnvironmentObject

🧠🔋

EnvironmentObject

我们的 @State 是 View 本身创建的变量,可以更新 View,而 @Binding 是和父 View 的值绑定的变量,可以更新View,而 @ObservedObject 和 @StateObject 也是可以更新 View。那么 @Environmentobject 也是可以更新 View 的Property Wrapper。

从字面意思可以理解,@Environmentobject 是存放在应用环境里的 Object,既然是存在应用里我们就可以在任何一个View 里获取到这个 Object,比如一个变量我们要在很多个页面之后用到,那么我们就不需要在中间的每个页面都传递到下一个页面,直接在最后一个用到的 View 里使用@EnvironmentObject 获取到。

创建使用

class DesignUser: ObservableObject {
    @Published var number: Int = 0
}
struct EnvironmentObjectView: View {
    @StateObject var user = DesignUser()
    @State var show = false
    var body: some View {
        VStack(spacing: 16) {
            Text("Number: \(user.number)")
            Button("下一个页面") {
                show.toggle()
            }
        }
        .sheet(isPresented: $show) {
            SecondView()
        }
        .environmentObject(user)// 核心在这里,一定要记得给视图共享数据
    }
}
struct SecondView: View {
    @State var show = false
    var body: some View {
        Button("下一个页面") {
            show.toggle()
        }.sheet(isPresented: $show) {
            ThirdView()
        }
    }
}

struct ThirdView: View {
    @EnvironmentObject var user: DesignUser
    var body: some View {
        Button("增加数字") {
            user.number += 1
        }
    }
}

可以看到在第一个页面,我们创建了一个 StateObject 的 user 并且设置为 .environmentObject(user),这样在加载第二个页面在加载第三个页面之后,我们就可以直接在第三个页面使用 @EnvironmentObject var user: DesignUser获取到User,更新之后第一个页面也会同样更新。

注意 @EnvironmentObject 只能向后面的 View 传递,而不能向前面,一般我们需要用的时候,可以直接在 App
的初始化的时候设置 .environmentObject,这样在后面的所有页面都可以使用。

另外上面的这种情况里,如果我们的 .environmentObject 在 .sheet 之前设置,后面就无法获取到。

.sheet

在某些版本里当我们使用.sheet 加载页面的时候,如果下拉一半页面在放开,这个时候就丢失了
EnvironmentObject,如果有操作就会崩溃,如果遇到这种情况,可以在我们通过.sheet 加载的页面里设置一
下 .environmentObject 就可以避免。

例如上面的第二个 View 里我们可以设置如下:

struct SecondView: View {
    @State var show = false
    @EnvironmentObject var user: DesignUser
    var body: some View {
        Button("下一个页面") {
            show.toggle()
        }.sheet(isPresented: $show) {
            ThirdView()
                .environmentObject(user)
        }
    }
}