简体   繁体   English

SwiftUI:对同一变量使用不同的属性包装器

[英]SwiftUI: Using different property wrappers for the same variable

in iOS13 I do the following to bind my View to my model:在 iOS13 中,我执行以下操作将我的视图绑定到我的模型:

class MyModel: ObservableObject {
    @Published var someVar: String = "initial value"
}

struct MyView: View {
    @ObservedObject var model = MyModel()
    
    var body: some View {
        Text("the value is \(model.someVar)")
    }
}

in iOS14 there is a new property wrapper called @StateObject that I can use in the place of @ObservedObject , I need this snippet of code to be compatible with iOS13 and iOS14 while leveraging iOS14's new feature, how can I do that with @StateObject for the same variable ?在 iOS14 中有一个名为@StateObject的新属性包装器,我可以使用它来代替@ObservedObject ,我需要这段代码与 iOS13 和 iOS14 兼容,同时利用 iOS14 的新功能,我如何使用@StateObject做到这@StateObject相同的变量?

Different property wrappers generate different types of hidden properties, so you cannot just conditionally replace them.不同的属性包装器会生成不同类型的隐藏属性,因此您不能只是有条件地替换它们。 Here is a demo of possible approach.这是可能的方法的演示。

Tested with Xcode 12 / iOS 14 (deployment target 13.6)使用 Xcode 12 / iOS 14 测试(部署目标 13.6)

struct ContentView: View {
    var body: some View {
        if #available(iOS 14, *) {
            MyNewView()
        } else {
            MyView()
        }
    }
}

class MyModel: ObservableObject {
    @Published var someVar: String = "initial value"
}

@available(iOS, introduced: 13, obsoleted: 14, renamed: "MyNewView")
struct MyView: View {

    @ObservedObject var model = MyModel()

    var body: some View {
        CommonView().environmentObject(model)
    }
}

@available(iOS 14, *)
struct MyNewView: View {

    @StateObject var model = MyModel()

    var body: some View {
        CommonView().environmentObject(model)
    }
}

struct CommonView: View {
    @EnvironmentObject var model: MyModel

    var body: some View {
        Text("the value is \(model.someVar)")
    }
}

ObservableObject and @Published are part of the Combine framework and you should only use those when you require a Combine pipeline to assign the output to the @Published var. ObservableObject@Published是Combine 框架的一部分,只有在需要Combine 管道assign输出assign @Published时才应该使用它们。 What you should be using for your data is @State use it as follows:你应该为你的数据使用的是@State使用它如下:

struct MyView: View {
    @State var text = "initial value"
    
    var body: some View {
        VStack{
            Text("the value is \(text)")
            TextField("", text: $text)
        }
    }
}

If you have multiple vars or need functions then you should refactor these into their own struct.如果您有多个变量或需要函数,那么您应该将它们重构为它们自己的结构。 Multiple related properties in their own struct makes the View more readable, can maintain invariance on its properties and be tested independently.多个相关属性在它们自己的结构中使视图更具可读性,可以保持其属性的不变性并独立测试。 And because the struct is a value type, any change to a property, is visible as a change to the struct (Learn this in WWDC 2020 Dataflow Through SwiftUI ).并且由于结构是值类型,因此对属性的任何更改都可以作为结构的更改可见(在WWDC 2020 Dataflow Through SwiftUI 中了解这一点)。 Implement as follows:执行如下:

struct MyViewConfig {
    var text1 = "initial value"
    var text2 = "initial value"

    mutating func reset(){
        text1 = "initial value"
        text2 = "initial value"
    }
}

struct MyView: View {
    @Binding var config: MyViewConfig
    
    var body: some View {
        VStack{
            Text("the value is \(config.text1)")
            TextField("", text: $config.text1)
            Button("Reset", action: reset)
        }
    }

    func reset() {
        config.reset()
    }
}

struct ContentView {
    @State var config = MyViewConfig()
    var body: some View {
        MyView(config:$config)
    }
}

SwiftUI is designed to take advantage of value semantics where all the data is in structs which makes it run super fast. SwiftUI 旨在利用值语义,其中所有数据都在结构中,这使其运行速度超快。 If you unnecessarily create objects then you are slowing it all down.如果你不必要地创建对象,那么你就会减慢它的速度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM