SwiftUI - 更改 @Published 结构时是不是可以触发 didSet?
Posted
技术标签:
【中文标题】SwiftUI - 更改 @Published 结构时是不是可以触发 didSet?【英文标题】:SwiftUI - is it possible to get didSet to fire when changing a @Published struct?SwiftUI - 更改 @Published 结构时是否可以触发 didSet? 【发布时间】:2020-07-10 22:28:47 【问题描述】:我刚刚更新到 XCode 11.4,我的一些代码已经停止工作。我在ObservableObject
中有一些@Published
结构变量。以前,当我更新结构上的属性时,didSet
方法会在发布的属性上触发,但现在情况不再如此。这种行为是否有可能在 Swift 的最新更新中被设计改变了?
这是一个简单的例子:
import SwiftUI
struct PaddingRect
var left: CGFloat = 20
var right: CGFloat = 20
final class SomeStore : ObservableObject
@Published var someOtherValue: String = "Waiting for didSet"
@Published var paddingRect:PaddingRect = PaddingRect()
didSet
someOtherValue = "didSet fired"
struct ObserverIssue: View
@ObservedObject var store = SomeStore()
var body: some View
VStack
Spacer()
Rectangle()
.fill(Color.yellow)
.padding(.leading, store.paddingRect.left)
.padding(.trailing, store.paddingRect.right)
.frame(height: 100)
Text(store.someOtherValue)
HStack
Button(action:
// This doesn't call didSet
self.store.paddingRect.left += 20
// This does call didSet, ie. setting the whole thing
// self.store.paddingRect = PaddingRect(
// left: self.store.paddingRect.left + 20,
// right: self.store.paddingRect.right
// )
)
Text("Padding left +20")
Button(action:
self.store.paddingRect.right += 20
)
Text("Padding right +20")
Spacer()
struct ObserverIssue_Previews: PreviewProvider
static var previews: some View
ObserverIssue()
属性更新,但didSet
没有触发。
是否可以获取结构体的嵌套属性来触发发布者的didSet
方法?
【问题讨论】:
奇怪的是,在我升级之前它一直在我的代码中工作,仅此而已。当您看到我的实际问题是“是否可以获取结构的嵌套属性以触发发布者的 didSet 方法”时,我将更改问题的标题 @Asperi:我遇到了同样的问题......并且在我更新之前调用了 didSet - 这是真的。也许之前是一个错误......但它有效;)我喜欢这个功能,我错过了...... 看看这个:***.com/a/59391476/8457280。 -> 然后它再次工作;) 【参考方案1】:您可以在课程本身中订阅@Published
价值流。
final class SomeStore: ObservableObject
@Published var someOtherValue: String = "Waiting for didSet"
@Published var paddingRect: PaddingRect = PaddingRect()
private var subscribers: Set<AnyCancellable> = []
init()
$paddingRect.sink paddingRect in
print(paddingRect) // ?
.store(in: &subscribers)
【讨论】:
记住Published.Publisher
(通过$paddingRect
访问)是实现willSet,而不是didSet。
@DávidPásztor 是的,这种预期差异可能会导致令人讨厌的细微错误:forums.swift.org/t/is-this-a-bug-in-published/31292【参考方案2】:
属性观察者观察属性。麻烦来自与属性包装器相关的新 Swift 语法。在您的情况下,您尝试观察 Published 的值(这是一个定义专用属性包装器的结构)是否发生了变化,而不是包装属性的值。
如果需要监控PaddingRect中的left或right值,直接观察这个值即可。
import SwiftUI
struct PaddingRect
var left: CGFloat = 20
didSet
print("left padding change from:", oldValue, "to:", left)
var right: CGFloat = 20
didSet
print("right padding change from:", oldValue, "to:", right)
final class SomeStore : ObservableObject
@Published var someOtherValue: String = "Waiting for didSet"
@Published var paddingRect:PaddingRect = PaddingRect()
struct ContentView: View
@ObservedObject var store = SomeStore()
var body: some View
VStack
Spacer()
Rectangle()
.fill(Color.yellow)
.padding(.leading, store.paddingRect.left)
.padding(.trailing, store.paddingRect.right)
.frame(height: 100)
Text(store.someOtherValue)
HStack
Button(action:
// This doesn't call didSet
self.store.paddingRect.left += 20
// This does call didSet, ie. setting the whole thing
self.store.paddingRect = PaddingRect(
left: self.store.paddingRect.left + 20,
right: self.store.paddingRect.right
)
)
Text("Padding left +20")
Button(action:
self.store.paddingRect.right += 20
)
Text("Padding right +20")
Spacer()
struct ContentView_Preview: PreviewProvider
static var previews: some View
ContentView()
或利用已发布的预计值是发布者并将下一个修饰符应用于任何视图
.onReceive(store.$paddingRect) (p) in
print(p)
【讨论】:
以上是关于SwiftUI - 更改 @Published 结构时是不是可以触发 didSet?的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:“@Published”属性更改时未刷新“带有组的动态列表”
当视图模型@Published 更改时,SwiftUI 列表因“NSRangeException”而崩溃
当我通过鼠标单击更改 SwiftUI 列表的选择时,@Published 属性的 didSet 被调用了两次
当我的@Published NSManagedObjects 数组更改时,我的 SwiftUI 列表不会更新