【问题标题】:How to use published optional properties correctly for SwiftUI如何为 SwiftUI 正确使用已发布的可选属性
【发布时间】:2021-10-07 22:46:53
【问题描述】:

为了提供一些上下文,我在我们的应用程序中编写了一个订单跟踪部分,它每隔一段时间就会从服务器重新加载订单状态。屏幕上的 UI 是在 SwiftUI 中开发的。我需要屏幕上的可选图像,该图像会随着订单在状态中的进展而变化。

当我尝试以下一切正常...

我的 viewModel 是一个 ObservableObject: internal class MyAccountOrderViewModel: ObservableObject {

这有一个发布的属性: @Published internal var graphicURL: URL = Bundle.main.url(forResource: "tracking_STAGEONE", withExtension: "gif")!

在 SwiftUI 中使用如下属性: GIFViewer(imageURL: $viewModel.graphicURL)


我的问题是graphicURL 属性的占位符值可能不正确,我的要求是它是可选的。将发布的属性更改为:@Published internal var graphicURL: URL? 会导致我的 GIFViewer 出现问题,该问题正确地不接受可选 URL:

Cannot convert value of type 'Binding<URL?>' to expected argument type 'Binding<URL>'

尝试对graphicURL 进行明显的解包会产生此错误:

Cannot force unwrap value of non-optional type 'Binding<URL?>'


什么是使这项工作的正确方法?我不想在属性中输入一个值,并检查该属性是否等于占位符值(即将其视为 nil),或者假设该属性始终为非 nil 并且不安全地强制以某种方式展开它。

【问题讨论】:

  • 如果 URL 是nil,您希望做什么?你必须以某种方式处理它
  • 问题是如果它是可选的则不起作用,如果 url 为 nil 我会绕过 SwiftUI 定义的那部分。
  • 所以你几乎想要if let x = ... 之类的Binding

标签: swiftui observedobject swift-optionals


【解决方案1】:

下面是Binding 的扩展,您可以使用它来将Binding<Int?> 之类的类型转换为Binding<Int>?。在您的情况下,它将是 URL 而不是 Int,但此扩展是通用的,因此适用于任何 Binding

extension Binding {
    func optionalBinding<T>() -> Binding<T>? where T? == Value {
        if let wrappedValue = wrappedValue {
            return Binding<T>(
                get: { wrappedValue },
                set: { self.wrappedValue = $0 }
            )
        } else {
            return nil
        }
    }
}

带有示例视图:

struct ContentView: View {
    @StateObject private var model = MyModel()

    var body: some View {
        VStack(spacing: 30) {
            Button("Toggle if nil") {
                if model.counter == nil {
                    model.counter = 0
                } else {
                    model.counter = nil
                }
            }

            if let binding = $model.counter.optionalBinding() {
                Stepper(String(binding.wrappedValue), value: binding)
            } else {
                Text("Counter is nil")
            }
        }
    }
}

class MyModel: ObservableObject {
    @Published var counter: Int?
}

结果:

【讨论】:

  • 感谢您写得很好且很有帮助的回复!
猜你喜欢
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
  • 2020-05-21
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
相关资源
最近更新 更多