我用的是
DecimalField
在我的应用程序中放置文本字段。但是,如果我将它与环境对象一起使用,应用程序会因内存泄漏而冻结。
这是我的模型:
class PaymentPlan: ObservableObject {
@Published var amountBorrowed: Decimal?
}
这是我的内容视图:
var currencyFormatter: NumberFormatter {
let nf = NumberFormatter()
nf.numberStyle = .currency
nf.isLenient = true
return nf
}
struct ContentView: View {
@EnvironmentObject var paymentPlan: PaymentPlan
static var currencyFormatter: NumberFormatter {
let nf = NumberFormatter()
nf.numberStyle = .currency
nf.isLenient = true
return nf
}
var body: some View {
DecimalField("Placeholder", value: $paymentPlan.amountBorrowed, formatter: Self.currencyFormatter)
}
}
这是我正在使用的自定义文本字段(源代码):
import SwiftUI
import Combine
struct DecimalField : View {
let label: LocalizedStringKey
@Binding var value: Decimal?
let formatter: NumberFormatter
let onEditingChanged: (Bool) -> Void
let onCommit: () -> Void
// The text shown by the wrapped TextField. This is also the "source of
// truth" for the `value`.
@State private var textValue: String = ""
// When the view loads, `textValue` is not synced with `value`.
// This flag ensures we don't try to get a `value` out of `textValue`
// before the view is fully initialized.
@State private var hasInitialTextValue = false
init(
_ label: LocalizedStringKey,
value: Binding<Decimal?>,
formatter: NumberFormatter,
onEditingChanged: @escaping (Bool) -> Void = { _ in },
onCommit: @escaping () -> Void = {}
) {
self.label = label
_value = value
self.formatter = formatter
self.onEditingChanged = onEditingChanged
self.onCommit = onCommit
}
var body: some View {
TextField(label, text: $textValue, onEditingChanged: { isInFocus in
// When the field is in focus we replace the field's contents
// with a plain unformatted number. When not in focus, the field
// is treated as a label and shows the formatted value.
if isInFocus {
self.textValue = self.value?.description ?? ""
} else {
let f = self.formatter
let newValue = f.number(from: self.textValue)?.decimalValue
self.textValue = f.string(for: newValue) ?? ""
}
self.onEditingChanged(isInFocus)
}, onCommit: {
self.onCommit()
})
.onReceive(Just(textValue)) {
guard self.hasInitialTextValue else {
// We don't have a usable `textValue` yet -- bail out.
return
}
// This is the only place we update `value`.
self.value = self.formatter.number(from: $0)?.decimalValue
}
.onAppear(){ // Otherwise textfield is empty when view appears
self.hasInitialTextValue = true
// Any `textValue` from this point on is considered valid and
// should be synced with `value`.
if let value = self.value {
// Synchronize `textValue` with `value`; can't be done earlier
self.textValue = self.formatter.string(from: NSDecimalNumber(decimal: value)) ?? ""
}
}
.keyboardType(.decimalPad)
}
}
有什么不好的建议吗?文本字段与@State完美结合。