SwiftUI:为什么 @AppStorage 的工作方式与我的自定义绑定不同?

SwiftUI: Why does @AppStorage work differently to my custom binding?

我有一个模式 Sheet,它应该基于 UserDefault 布尔值显示。 我写了一个 UI-Test 来消除 sheet 并且我使用启动参数来控制默认值。

然而,当我最初尝试使用 @AppStorage 时,它似乎并没有保留该值,或者是偷偷地不写它?我的测试失败了,因为在 'dismissing' 模式弹出后,值没有改变。

为了解决这个问题,我编写了一个自定义绑定。但我不确定这两种实现之间的行为差​​异是什么?这样测试就通过了。

有人知道我不明白什么吗?

干杯!

简单示例

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。自定义绑定:

struct ContentView: View {
  var body: some View {
    let binding = Binding<Bool> {
        UserDefaults.standard.bool(forKey: "should.show.sheet")
    } set: {
        UserDefaults.standard.set([=11=], forKey: "should.show.sheet")
    }
      
    Text("Content View")
      .sheet(isPresented: binding) {
        Text("Sheet")
      }
  }
}

测试用例:

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)
  }
}
  1. 即使 运行 应用程序也不起作用,因为那个“.”在键名中(看起来这是 AppStorage 的限制,所以使用简单的符号,如 isSheet.

  2. IMO test-case 不正确,因为它通过参数域覆盖默认值,但它是 read-only,因此尝试写入持久域,但可能存在那里有相同的值,因此不会生成更改(读取 didSet)事件,因此 UI.

    中没有更新
  3. 要对此进行测试,它应该是 inside 应用程序的配对事件,即。一个给出 AppStoragetrue,另一个给出 false

*注意:布尔值在参数中显示为 0/1(不是 XML),即 -isSheet 1