SwiftUI - возможно ли, чтобы didSet срабатывал при изменении структуры @Published?
Я только что обновился до XCode 11.4, и часть моего кода перестала работать. у меня есть немного@Published
структурные переменные в ObservableObject
. Раньше, когда я обновлял свойства в структуре,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
метод издателя?
2 ответа
Наблюдатель за недвижимостью наблюдает за собственностью. Проблема связана с новым синтаксисом Swift, связанным с оболочками свойств. В вашем случае вы пытаетесь наблюдать, изменилось ли значение опубликованного (который является структурой, определяющей специализированную оболочку свойств), а не значение обернутого свойства.
Если вам нужно отслеживать значения влево или вправо в 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()
}
}
Или воспользуйтесь преимуществом того, что опубликованное прогнозируемое значение - Издатель, и примените модификатор next к любому представлению.
.onReceive(store.$paddingRect) { (p) in
print(p)
}
Вы можете подписаться на @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)
}
}