SwiftUI - 是否有可能在更改 @Published 结构时触发 didSet?
SwiftUI - is it possible to get didSet to fire when changing a @Published struct?
我刚刚更新到 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
方法?
属性 观察者观察 属性。问题来自与 属性 包装器相关的新 Swift 语法。在您的情况下,您尝试观察 Published 的值(它是定义专用 属性 包装器的结构)是否发生了变化,而不是包装的 属性.
的值
如果您需要监控 PaddingRect 中的左值或右值,直接观察该值即可。
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()
}
}
或者利用 Published projected value is Publisher 并将 next modifier 应用于任何 View
.onReceive(store.$paddingRect) { (p) in
print(p)
}
您可以在 class 本身中订阅 @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)
}
}
Note that the sink
closure will be called on willSet
, though.
我刚刚更新到 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
方法?
属性 观察者观察 属性。问题来自与 属性 包装器相关的新 Swift 语法。在您的情况下,您尝试观察 Published 的值(它是定义专用 属性 包装器的结构)是否发生了变化,而不是包装的 属性.
的值如果您需要监控 PaddingRect 中的左值或右值,直接观察该值即可。
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()
}
}
或者利用 Published projected value is Publisher 并将 next modifier 应用于任何 View
.onReceive(store.$paddingRect) { (p) in
print(p)
}
您可以在 class 本身中订阅 @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)
}
}
Note that the
sink
closure will be called onwillSet
, though.