使用 @Binding var 初始化 SwiftUI 类

Posted

技术标签:

【中文标题】使用 @Binding var 初始化 SwiftUI 类【英文标题】:Init for a SwiftUI class with a @Binding var 【发布时间】:2020-11-10 08:47:43 【问题描述】:

我有一个类,我想用另一个视图中设置的绑定变量来初始化它。

查看->

struct CoverPageView: View 
    @State  var numberOfNumbers:Int

    var body: some View 
        NavigationView 
            GeometryReader  geometry in
                VStack(alignment: .center, spacing: 0)
                    TextField("Multiplication Upto:", value: self.$numberOfNumbers, formatter: NumberFormatter())

                
            
        
    

需要使用 @Binding var $numberofNumbers 初始化的类 -

import SwiftUI

class MultiplicationPractice:ObservableObject 

    @Binding var numberOfNumbers:Int
    var classNumofNumbers:Int

    init() 
        self.classNumofNumbers = self.$numberOfNumbers
    

init 语句显然给出了 self 未初始化的错误,并且正在使用实例 var 进行初始化,这是不允许的。

我该如何规避这个问题?该类需要使用用户在第一个视图中输入的数字进行初始化。我写了大约。代码在这里,请忽略任何错别字。

【问题讨论】:

你不要用var classNumofNumbers:Int传递,直接从init函数传递。 MultiplicationPractice(numberOfNumbers: $numberOfNumbers) 抱歉 - 我这样展示它是因为实际的类有同一个类的已发布 var。一旦我将 $numOfNumbers 传递给初始化程序 - 它就会给出 self is not initialized 错误 - 如果你想用绑定值初始化一个 var 也是一样的。 -- --类似于 - import SwiftUI class MultiplicationPractice:ObservableObject Binding var numberOfNumbers:Int Published var MulGame:MultiplicationGame = MultiplicationGame(maxNumber: $numberofNumbers) // - 这是它给出错误的地方 【参考方案1】:

通常您会在 CoverPageView 中使用起始值初始化 MultiplicationPractice:

@ObservedObject var someVar = MultiplicationPractice(NoN:123)

当然,还要添加一个支持性的 init 语句:

class MultiplicationPractice:ObservableObject 
    init(NoN: Int) 
        self.numberOfNumbers = val
    

你不想用@Binding 包装你的var,而是用@Published 包装它:

class MultiplicationPractice:ObservableObject 

@Published var numberOfNumbers:Int
...

在您的特定情况下,我什至会在您的CoverPageView 中删除numberOfNumbers var,而是使用上述someVar 的直接变量:

struct CoverPageView: View 
    //removed @State  var numberOfNumbers:Int
    @ObservedObject var someVar = MultiplicationPractice(123)
    
    ...
    
    TextField("Multiplication Upto:", value: self.$someVar.numberOfNumbers, formatter: NumberFormatter())

您会注意到我将@ObservedObject 的子变量作为绑定传入。我们可以用 ObservableObjects 做到这一点。


编辑

我现在看到了你想要做什么,你想在你的 ViewModel 中传递一个绑定,并在你的视图和模型之间建立一个间接的连接。虽然这可能不是我个人的做法,但我仍然可以提供一个可行的示例。

这是一个使用结构名称的简单示例:

struct MultiplicationGame 
    @Binding var maxNumber:String
    init(maxNumber: Binding<String>) 
        self._maxNumber = maxNumber
        print(self.maxNumber)
    


class MultiplicationPractice:ObservableObject 
    var numberOfNumbers: Binding<String>
    @Published var MulGame:MultiplicationGame
    
    init(numberOfNumbers: Binding<String> ) 
        self.numberOfNumbers = numberOfNumbers
        self.MulGame = MultiplicationGame(maxNumber: numberOfNumbers)
    
    

struct ContentView: View 
    @State var someText: String
    @ObservedObject var mulPractice: MultiplicationPractice
    init() 
        let state = State(initialValue: "")
        self._someText = state
        self.mulPractice = MultiplicationPractice(numberOfNumbers: state.projectedValue)
    
    var body: some View 
        TextField("put your text here", text: $someText)
    

【讨论】:

感谢您抽出时间回复 - 抱歉代码混乱。 - 封面浏览量是主要的(事实) - 这是用户输入 numberOfNumbers 的地方。类 MultiplicationPractice 是我的视图模型,它需要这个 numberofNumbers 才能访问没有视图主体的模型(另一个结构)。所以乘法练习是数据应该流向而不是相反的练习。 这是类 - import SwiftUI class MultiplicationPractice:ObservableObject Binding var numberOfNumbers:Int Published var MulGame:MultiplicationGame = MultiplicationGame(maxNumber: $numberofNumbers) // - 这是它给出错误的地方 - 我明白了。因此,您有效地尝试将 numberOfNumbers 从视图传递到视图模型,然后最终从视图模型传递到模型。我会更新我的答案。 这太好了-谢谢。代码编译并工作。我似乎仍然遇到无法超出初始值的问题。例如,如果我将状态的初始值设置为 10 - 然后如果用户输入 11 - 那么我的所有数组索引开始超出范围,而如果用户输入 9 - 那么没有问题并且视图生成正常! 【参考方案2】:

好的,我不太明白你的问题,所以我只列出几个例子,希望其中一个就是你要找的。​​p>


struct SuperView: some View 
    @State var value: Int = 0

    var body: some View 
        SubView(value: self.$value)
    

struct SubView: View 
    @Binding var value: Int

    // This is the same as the compiler-generated memberwise initializer
    init(value: Binding<Int>) 
        self._value = value
    

    var body: some View 
        Text("\(value)")
    


如果我误解了,而您只是想获取当前值,请执行此操作

struct SuperView: some View 
    @State var value: Int = 0

    var body: some View 
        SubView(value: self.value)
    

struct SubView: View 
    let value: Int

    // This is the same as the compiler-generated memberwise initializer
    init(value: Int) 
        self.value = value
    

    var body: some View 
        Text("\(value)")
    

【讨论】:

感谢您的回复 - 很抱歉代码混乱。 - 封面浏览量是主要的(事实) - 这是用户输入 numberOfNumbers 的地方。类 MultiplicationPractice 是我的视图模型,它需要这个 numberofNumbers 才能访问没有视图主体的模型(另一个结构)。所以乘法练习是数据应该流向而不是相反的练习。 您的示例 sn-p 正在使用两个视图 - 但我有一个视图和一个类 - 我有一个从用户那里获取值的视图 - 然后这个值需要传递给一个类. (问题主要也是因为作为一个类,它需要初始化所有变量) 恐怕我还是不太明白——也许您可以使用我在示例中提出的相同想法,或者@Samuel-IH 的回答可能对您有所帮助

以上是关于使用 @Binding var 初始化 SwiftUI 类的主要内容,如果未能解决你的问题,请参考以下文章

Swift / SwiftUI:如何检查环境 /binding var 是不是为空字符串(.isEmpty 出现构建错误)

为啥在 Swift 中使用惰性 var 初始化时添加框架不显示 UIView

Swift: let 未初始化,但 var 已初始化。为啥? [复制]

Swift 中 @Binding 变量的 didSet

Swift3,展开 Optional<Binding>(在 SQLite.swift 中)

让 swift @Binding 接受任何符合 `BinaryFloatingPoint` 的值?