Skip to content

Commit 0811a5d

Browse files
authored
Display a deprecation warning and fatal error when the top-level @Environment(\.viewEnvironment) is referenced (#319)
Display a deprecation warning and fatal error when the top-level `@Environment(\.viewEnvironment)` is referenced, to enforce people reference a sub-property. This ensures proper SwiftUI view invalidation.
1 parent 89d60fc commit 0811a5d

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

ViewEnvironment/Sources/EnvironmentValues+ViewEnvironment.swift

+22
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,26 @@ extension EnvironmentValues {
2929
}
3030
}
3131

32+
extension Environment where Value == ViewEnvironment {
33+
@available(
34+
*,
35+
deprecated,
36+
message:
37+
"""
38+
Please do not create an `@Environment` property that references the top-level `viewEnvironment`: \
39+
it will break SwiftUI's automatic invalidation when any part of the `ViewEnvironment` changes. \
40+
Instead, reference your relevant sub-property, eg `@Environment(\\.viewEnvironment.myProperty)`.
41+
"""
42+
)
43+
@inlinable public init(_ keyPath: KeyPath<EnvironmentValues, Value>) {
44+
fatalError(
45+
"""
46+
Please do not create an `@Environment` property that references the top-level `viewEnvironment`: \
47+
it will break SwiftUI's automatic invalidation when any part of the `ViewEnvironment` changes. \
48+
Instead, reference your relevant sub-property, eg `@Environment(\\.viewEnvironment.myProperty)`.
49+
"""
50+
)
51+
}
52+
}
53+
3254
#endif

WorkflowSwiftUI/Tests/ObservableScreenTests.swift

+10-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ private struct TestKey: ViewEnvironmentKey {
3939
static var defaultValue: Int = 0
4040
}
4141

42+
extension ViewEnvironment {
43+
fileprivate var testKey: Int {
44+
get { self[TestKey.self] }
45+
set { self[TestKey.self] = newValue }
46+
}
47+
}
48+
4249
@ObservableState
4350
private struct MyState {
4451
var emittedValue: TestKey.Value?
@@ -62,14 +69,14 @@ private struct TestKeyEmittingScreen: ObservableScreen {
6269
}
6370

6471
struct ContentView: View {
65-
@Environment(\.viewEnvironment)
66-
var viewEnvironment: ViewEnvironment
72+
@Environment(\.viewEnvironment.testKey)
73+
var testValue: Int
6774

6875
var store: Store<Model>
6976

7077
var body: some View {
7178
WithPerceptionTracking {
72-
let _ = { store.emittedValue = viewEnvironment[TestKey.self] }()
79+
let _ = { store.emittedValue = testValue }()
7380
Color.clear
7481
.frame(width: 1, height: 1)
7582
}

WorkflowSwiftUIExperimental/Tests/SwiftUIScreenTests.swift

+11-3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ private struct TestKey: ViewEnvironmentKey {
8484
static var defaultValue: Int = 0
8585
}
8686

87+
extension ViewEnvironment {
88+
fileprivate var testKey: Int {
89+
get { self[TestKey.self] }
90+
set { self[TestKey.self] = newValue }
91+
}
92+
}
93+
8794
private struct ContentScreen: SwiftUIScreen {
8895
let sizingOptions: SwiftUIScreenSizingOptions
8996

@@ -103,13 +110,14 @@ private struct TestKeyEmittingScreen: SwiftUIScreen {
103110
}
104111

105112
struct ContentView: View {
106-
@Environment(\.viewEnvironment)
107-
var viewEnvironment: ViewEnvironment
113+
@Environment(\.viewEnvironment.testKey)
114+
var testValue: Int
108115

109116
var onTestKeyEmission: (TestKey.Value) -> Void
110117

111118
var body: some View {
112-
let _ = onTestKeyEmission(viewEnvironment[TestKey.self])
119+
let _ = onTestKeyEmission(testValue)
120+
113121
Color.clear
114122
.frame(width: 1, height: 1)
115123
}

0 commit comments

Comments
 (0)