当前位置: 首页 > 知识库问答 >
问题:

SwiftUI:如何使用@binding变量实现自定义init

宋俊艾
2023-03-14

我正在处理一个货币输入屏幕,需要实现一个自定义的init来根据初始化的金额设置一个状态变量。

我原以为这会起作用,但我得到了一个编译器错误:

struct AmountView : View {
    @Binding var amount: Double

    @State var includeDecimal = false

    init(amount: Binding<Double>) {
        self.amount = amount
        self.includeDecimal = round(amount)-amount > 0
    }
    ...
}

共有1个答案

袁增
2023-03-14

啊!你离得太近了。你就是这么做的。您错过了一个美元符号(Beta3)或下划线(Beta4),以及金额属性前面的self或金额参数后面的.value。所有这些选项都有效:

您将看到我删除了includedecimal中的@state,请检查末尾的解释。

这是使用属性(将self放在前面):

struct AmountView : View {
    @Binding var amount: Double
    
    private var includeDecimal = false
    
    init(amount: Binding<Double>) {

        // self.$amount = amount // beta 3
        self._amount = amount // beta 4

        self.includeDecimal = round(self.amount)-self.amount > 0
    }
}
struct AmountView : View {
    @Binding var amount: Double
    
    private var includeDecimal = false
    
    init(amount: Binding<Double>) {
        // self.$amount = amount // beta 3
        self._amount = amount // beta 4

        self.includeDecimal = round(amount.value)-amount.value > 0
    }
}

这是相同的,但是我们对参数(withAmount)和属性(amount)使用了不同的名称,所以您可以清楚地看到何时使用它们。

struct AmountView : View {
    @Binding var amount: Double
    
    private var includeDecimal = false
    
    init(withAmount: Binding<Double>) {
        // self.$amount = withAmount // beta 3
        self._amount = withAmount // beta 4

        self.includeDecimal = round(self.amount)-self.amount > 0
    }
}
struct AmountView : View {
    @Binding var amount: Double
    
    private var includeDecimal = false
    
    init(withAmount: Binding<Double>) {
        // self.$amount = withAmount // beta 3
        self._amount = withAmount // beta 4

        self.includeDecimal = round(withAmount.value)-withAmount.value > 0
    }
}

请注意,由于属性包装器(@binding),属性包装器创建的访问器使.value成为不必要的。但是,对于参数,就没有这样的事情了,您必须显式地执行它。如果您想了解更多关于属性包装器的信息,请查看WWDC Session415-Modern Swift API Design并跳转到23:12。

正如您所发现的,从初始化器修改@State变量将引发以下错误:线程1:致命错误:访问view.body外的状态。为了避免这种情况,您应该删除@state。这是有道理的,因为includeDecimal不是真理的来源。它的价值是由金额导出的。但是,通过删除@state,如果数量发生变化,includedecimal将不会更新。要实现这一点,最好的选择是将includeDecimal定义为一个计算属性,这样它的值就从真值的来源(量)派生出来。这样,每当金额发生变化时,您的includeDecimal也会发生变化。如果您的视图依赖于includeDecimal,它应该在更改时更新:

struct AmountView : View {
    @Binding var amount: Double
    
    private var includeDecimal: Bool {
        return round(amount)-amount > 0
    }
    
    init(withAmount: Binding<Double>) {
        self.$amount = withAmount
    }

    var body: some View { ... }
}

正如rob mayoff所指出的,您还可以使用$$varname(Beta3)或_varname(beta4)来初始化状态变量:

// Beta 3:
$$includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)

// Beta 4:
_includeDecimal = State(initialValue: (round(amount.value) - amount.value) != 0)
 类似资料:
  • 找到价格最高和最低的信息: mysql> SELECT @min_price:=MIN(price),@max_price:=MAX(price) FROM shop; mysql> SELECT * FROM shop WHERE [email protected]_price OR [email protected]_price; +---------+--------+-------+ |

  • 我需要实现我的自定义DefaultComboxModel。这样做的原因是每次我打电话给 或者 或者 我看到它自动触发一个项目状态更改事件。这会导致一些随机项目自动从列表中选择。这不是我想要的,因为它用随机选择的项目填充可编辑的JTextField。 这是我在使用我的自定义Itemlistener中的Thread.dumpStack()进行调试时看到的stacktrace,它是我在调用上述方法时看到

  • 我正在使用Spring开发一个应用程序。在Access Control Access一节中,我想使用Spring Security Acl(我是Acl的新手)。我想在我的应用程序中实现ACL基于两点: 应用程序应该具有以下五种权限:、、、和。 权限是分层的,当用户具有权限时,它应该能够,或者当用户具有权限时,它应该能够、和等。 更新: 我的应用程序是基于Spring MVC RESTful的。当用

  • 问题内容: 假设我在网站的各个页面上使用了三种单独的配色方案。每种颜色都有浅,中和深三种色调,并且配色方案由体内的类别定义。假定默认为“红色”配色方案。像这样: 颜色定义 : 基本默认样式示例 不同的配色方案样式示例 我想使用变量,这样我就不必为每种方案重新编写所有的颜色变化,这样我就可以编写如下内容: …但是我不太了解如何完成这项工作。帮帮我…? 问题答案: 在选择器和参数混合中使用插值和转义,

  • 问题内容: 到目前为止,我一直在使用SwiftUI并了解etc 的概念(至少我希望我这样做)。 我遇到了一个愚蠢的问题,似乎找不到以下答案:如何初始化变量? 我有以下代码: 在我的预览代码中,我想传递该类型的参数: 我将如何进行初始化?尝试过: 甚至: 但是没有一个…有什么想法吗? 问题答案: 在您的应用中使用时,您确实需要提供一些绑定,例如上一个视图中的或。 对于仅需要固定值的特殊情况,可以使用

  • 问题内容: 我要实现ActionBar必须如下所示的自定义: 所以问题: 如何实现类似自定义视图的按钮:仅显示一些图像? 如何在顶部绘制一条线? 以及如何实现不带分隔线的按钮:在上添加标签或添加什么? 问题答案: 如果要使用ActionBarAPI,这几乎与你将获得的接近。我不确定你是否可以在ActionBar不进行奇怪的Window黑客操作的情况下在其上方放置一个色带,这是不值得的。至于更改Me