@Published property wrapper not working on subclass of ObservableObject
I have a class conforming to the @ObservableObject protocol and created a subclass from it with it's own variable with the @Published property wrapper to manage state.
It seems that the @published property wrapper is ignored when using a subclass. Does anyone know if this is expected behaviour and if there is a workaround?
I'm running iOS 13 Beta 8 and xCode Beta 6.
Here is an example of what I'm seeing. When updating the TextField on MyTestObject
the Text view is properly updated with the aString value. If I update the MyInheritedObject
TextField the anotherString value isn't updated in the Text view.
import SwiftUI
class MyTestObject: ObservableObject {
@Published var aString: String = ""
}
class MyInheritedObject: MyTestObject {
@Published var anotherString: String = ""
}
struct TestObserverWithSheet: View {
@ObservedObject var myTestObject = MyInheritedObject()
@ObservedObject var myInheritedObject = MyInheritedObject()
var body: some View {
NavigationView {
VStack(alignment: .leading) {
TextField("Update aString", text: self.$myTestObject.aString)
Text("Value of aString is: \(self.myTestObject.aString)")
TextField("Update anotherString", text: self.$myInheritedObject.anotherString)
Text("Value of anotherString is: \(self.myInheritedObject.anotherString)")
}
}
}
}
Solution 1:
Finally figured out a solution/workaround to this issue. If you remove the property wrapper from the subclass, and call the baseclass objectWillChange.send() on the variable the state is updated properly.
NOTE: Do not redeclare let objectWillChange = PassthroughSubject<Void, Never>()
on the subclass as that will again cause the state not to update properly.
I hope this is something that will be fixed in future releases as the objectWillChange.send()
is a lot of boilerplate to maintain.
Here is a fully working example:
import SwiftUI
class MyTestObject: ObservableObject {
@Published var aString: String = ""
}
class MyInheritedObject: MyTestObject {
// Using @Published doesn't work on a subclass
// @Published var anotherString: String = ""
// If you add the following to the subclass updating the state also doesn't work properly
// let objectWillChange = PassthroughSubject<Void, Never>()
// But if you update the value you want to maintain state
// of using the objectWillChange.send() method provided by the
// baseclass the state gets updated properly... Jaayy!
var anotherString: String = "" {
willSet { self.objectWillChange.send() }
}
}
struct MyTestView: View {
@ObservedObject var myTestObject = MyTestObject()
@ObservedObject var myInheritedObject = MyInheritedObject()
var body: some View {
NavigationView {
VStack(alignment: .leading) {
TextField("Update aString", text: self.$myTestObject.aString)
Text("Value of aString is: \(self.myTestObject.aString)")
TextField("Update anotherString", text: self.$myInheritedObject.anotherString)
Text("Value of anotherString is: \(self.myInheritedObject.anotherString)")
}
}
}
}
Solution 2:
iOS 14.5 resolves this issue.
Combine
Resolved Issues
Using Published in a subclass of a type conforming to ObservableObject now correctly publishes changes. (71816443)
Solution 3:
This is because ObservableObject is a protocol, so your subclass must conform to the protocol, not your parent class
Example:
class MyTestObject {
@Published var aString: String = ""
}
final class MyInheritedObject: MyTestObject, ObservableObject {
@Published var anotherString: String = ""
}
Now, @Published properties for both class and subclass will trigger view events