自定义属性包装器无法准确反映我在 SwiftUI 中的 TextField 的状态,知道为啥吗?
Posted
技术标签:
【中文标题】自定义属性包装器无法准确反映我在 SwiftUI 中的 TextField 的状态,知道为啥吗?【英文标题】:Custom property wrapper not accurately reflecting the state of my TextField in SwiftUI, any idea why?自定义属性包装器无法准确反映我在 SwiftUI 中的 TextField 的状态,知道为什么吗? 【发布时间】:2020-08-18 00:32:56 【问题描述】:我创建了一个属性包装器,我想在其中插入一些逻辑,并且“set”值正在做正确的事情,但文本字段并未使用所有大写文本进行更新。文本字段不应该显示所有大写文本还是我误解了它是如何工作的?
这也是一个人为的例子,我的最终目标是在属性包装器中插入更多的逻辑,我只是使用大写的例子来让它工作。我在整个互联网上进行了搜索,但没有找到可行的解决方案。
import SwiftUI
import Combine
struct ContentView: View
@StateObject var vm = FormDataViewModel()
var body: some View
Form
TextField("Name", text: $vm.name)
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
class FormDataViewModel: ObservableObject
@Capitalized var name: String = ""
@propertyWrapper
public class Capitalized
@Published var value: String
public var wrappedValue: String
get value
set value = newValue.uppercased() //Printing this shows all caps
public var projectedValue: AnyPublisher<String, Never>
return $value
.eraseToAnyPublisher()
public init(wrappedValue: String)
value = wrappedValue
【问题讨论】:
【参考方案1】:SwiftUI 监视 @StateObject
或 @ObservedObject
中的 @Published
属性,并根据它们的变化触发 UI 更新。
但它并没有深入ObservableObject
。您的 FormDataViewModel
没有任何 @Published
属性。
您可以做的一件事是模拟@Published
对值变化的作用。
class FormDataViewModel: ObservableObject
@Capitalized var name: String = ""
private var nameObserver: AnyCancellable?
init()
nameObserver = _name.$value.sink _ in
self.objectWillChange.send()
请尝试。
【讨论】:
非常感谢!这行得通。我的印象是属性包装器可能是封装可重用逻辑的答案,但似乎我仍然需要使用支持变量来实现发布。【参考方案2】:这可以使用标准的@Published
来完成,看起来更简单、更可靠。
这里有一个解决方案。使用 Xcode 12 / ios 14 测试。
class FormDataViewModel: ObservableObject
@Published var name: String = ""
didSet
let capitalized = name.uppercased()
if name != capitalized
name = capitalized
objectWillChange.send()
【讨论】:
以上是关于自定义属性包装器无法准确反映我在 SwiftUI 中的 TextField 的状态,知道为啥吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何定义协议以包含带有 @Published 属性包装器的属性
带有选择器的 SwiftUI 列表:选择不适用于自定义类型(macOS)
深度解析:为何在 SwiftUI 视图的 init 初始化器里无法更改 @State 的值?