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

标签 swift swiftui xcuitest userdefaults

我有一个模式呈现的Sheet,它应该基于UserDefault bool 值显示。 我编写了一个 UI 测试,它会关闭该工作表,并使用启动参数来控制默认值。

但是,当我最初尝试使用 @AppStorage 时,它似乎没有保留该值,或者 secret 地没有写入它?我的测试失败了,因为“关闭”后,模式会弹出,因为值未更改。

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

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

干杯!

简单示例

<强>1。应用存储

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

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")
      }
  }
}

测试用例:

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 测试用例不正确,因为它通过参数域覆盖默认值,但它是只读的,因此尝试写入持久域,但那里可能有相同的值,所以没有变化( read didSet) 事件已生成,因此 UI 中没有更新。

  3. 要测试这一点,它应该在应用程序内部配对事件,即。一个给出 AppStoragetrue,另一个给出 false

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

关于SwiftUI:为什么 @AppStorage 的工作方式与我的自定义绑定(bind)不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72223809/

相关文章:

swift - 覆盖特定类型的可解码

mvvm - SwiftUI: View 模型不会更新 View

ios - SwiftUI - 我可以在 iPhone 上显示标签栏,在 iPad 上显示侧边栏吗?

swift - 在 Swift 4 的 XCUITest 中仅调用一次方法

ios - XCUITest:以协调的方式跨两个应用程序运行测试

ios - Swift 中的 NSSecureCoding(Facebook SDK)

xcode - 当变量具有特定值时触发函数

ios - 类型 'AppDelegate' 的值没有成员 'window'

macos - SwiftUI macOS 工具栏图标对齐三栏布局

ios - XCUITest - 如何检查 webview 是否已更新其内容?