'SwiftUI: Why does @AppStorage work differently to my custom binding?
I have a modal presented Sheet
which should display based on a UserDefault
bool.
I wrote a UI-Test which dismisses the sheet and I use launch arguments to control the defaults value.
However, when I tried using @AppStorage
initially it didn't seem to persist the value, or was secretly not writing it? My test failed as after 'dismissing' the modal pops back up as the value is unchanged.
To work around this I wrote a custom binding. But i'm not sure what the behaviour difference is between the two implementations? The test passes this way.
Does anyone know what i'm not understanding sorry?
Cheers!
Simple Example
1. AppStorage
struct ContentView: View {
@AppStorage("should.show.sheet") private var binding: Bool = true
var body: some View {
Text("Content View")
.sheet(isPresented: $binding) {
Text("Sheet")
}
}
}
2. Custom Binding:
struct ContentView: View {
var body: some View {
let binding = Binding<Bool> {
UserDefaults.standard.bool(forKey: "should.show.sheet")
} set: {
UserDefaults.standard.set($0, forKey: "should.show.sheet")
}
Text("Content View")
.sheet(isPresented: binding) {
Text("Sheet")
}
}
}
Test Case:
final class SheetUITests: XCTestCase {
override func setUpWithError() throws {
continueAfterFailure = false
}
func testDismiss() {
// Given 'true' userdefault value to show sheet on launch
let app = XCUIApplication()
app.launchArguments += ["-should.show.sheet", "<true/>"]
app.launch()
// When the user dismisses the modal view
app.swipeDown()
// Wait a second for animation (make sure it doesn't pop back)
sleep(1)
// Then the sheet should not be displayed
XCTAssertFalse(app.staticTexts["Sheet"].exists)
}
}
Solution 1:[1]
It does not work even when running app, because of that "." in key name (looks like this is AppStorage limitation, so use simple notation, like
isSheet
.IMO the test-case is not correct, because it overrides defaults by arguments domain, but it is read-only, so writing is tried into persistent domain, but there might be same value there, so no change (read
didSet
) event is generated, so there no update in UI.To test this it should be paired events inside app, ie. one gives
AppStorage
value true, other one gives false
*Note: boolean value is presented in arguments as 0/1 (not XML), lie -isSheet 1
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Asperi |