当应用于 Binding 时,在 SwiftUI 中展开可选的 @State

Giu*_*lli 4 ios swift swiftui

我正在寻找一个干净的解决方案来解决这个 SwiftUI 挑战。

以下代码可以编译,但无法工作,因为@State属性超出了ContentView范围。

import SwiftUI

struct ContentView: View {
  var state: LocalState?
  
  var body: some View {
    if let state = state {
      Toggle("Toggle", isOn: state.$isOn)
    }
  }
}

extension ContentView {
  struct LocalState {
    @State var isOn: Bool
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    VStack {
      ContentView(
        state: .init(isOn: false)
      )
      .border(Color.red)
      
      ContentView()
        .border(Color.red)
    }
    
  }
}
Run Code Online (Sandbox Code Playgroud)

由于以下原因,以下代码无法编译:

可选类型“ContentView.LocalState?”的值 必须展开以引用包装基类型“ContentView.LocalState”的成员“isOn”

似乎是$$state.isOn原件state而不是未包装

import SwiftUI

struct ContentView: View {
  @State var state: LocalState!
  
  var body: some View {
    if let state = state {
      Toggle("Toggle", isOn: $state.isOn)
    }
  }
}

extension ContentView {
  struct LocalState {
    var isOn: Bool
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    VStack {
      ContentView(
        state: .init(isOn: false)
      )
      .border(Color.red)
      
      ContentView()
        .border(Color.red)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我不想要的是:

  • 在 ContentView 中使用可失败的初始化程序。
  • isOn财产搬到外面LocalState

我怎样才能实现这些目标?

mal*_*hal 5

我相信这可以通过两种技术来解决。1. 使用 Binding 构造函数可以从可选绑定创建非可选绑定。2. 在预览中使用常量绑定,例如

import SwiftUI

struct Config {
    var isOn: Bool
}

struct ContentView: View {
    @State var config: Config?
    
    var body: some View {
        if let config = Binding($config) { // technique 1
            ContentView2(config: config)
        }
    }
}

struct ContentView2: View {
    @Binding var config: Config
    
    var body: some View {
        Toggle("Toggle", isOn: $config.isOn)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2(config: .constant(Config(isOn: false))) // technique 2
    }
}
Run Code Online (Sandbox Code Playgroud)