SwiftUI change on multilevel children Published object change
Observable objects don't just work when you have multiple levels of classes. The @Published
property wrapper notifies the view when the property has changed, but because this property is a class
- a reference type - it doesn't actually change when you change one of its properties. In other words, the reference remains the same.
And the inner @Published
doesn't do anything because there's nothing directly observing it (even if RecordingTimeManager
conformed to an ObservableObject
)
So, you either need to make RecordingTimeManager
a value-type - a struct
:
struct RecordingTimeManager {
var maxRecordingTime: TimeSeletedTime = .sixteenSeconds
}
Or, if it must be a class
(perhaps because it has some internal state and life cycle), then you could create an inner view that directly observes it.
First, it needs to be an ObservableObject
:
class RecordingTimeManager: ObservableObject {
@Published var maxRecordingTime: TimeSeletedTime = .sixteenSeconds
and then create a view (could be a private internal view) that observes it:
struct MainView: View {
@StateObject var appStatus: AppStatus = .init()
private struct InnerView: View {
@ObservedObject var recordingManager: RecordingTimeManager
var body: some View {
Button {
recordingManager.maxRecordingTime = .fifteenSeconds
} label: {
Text("15")
.font(Font.custom("BwGradual-Bold", size: 15))
.foregroundColor(
recordingManager.maxRecordingTime == .fifteenSeconds
? CLAPSOFFWHITE : TRIBESGREY)
}
}
}
var body: some View {
InnerView(recordingManager: appStatus.recordingTimeManager)
}
}
SwiftUI: How to change @Published object value. Changing a value of a published variable is not working
Solution
Change DCViewModel
to struct
.
Or if you have to keep it as a class
, make DCViewModel
conform to ObservableObject
, and keep a single reference in every singleView
. (which means you should subtract that row as a single View
)
Explanation
@Published is a property wrapper that publishes change message only when the wrapped value has been set.
The difference between value type and reference type: when you change a variable that holds a value type(struct), it has been set a new value actually. But when you change the value of a reference type(class), the variable that points to that object won't change.
That's why, in your case, when you add a new DCViewModel
to the Array
(value type), you are always setting a new value to that array, so @Published
takes effect. However, the wrapped value is DCViewModel
, which is a class(reference type). When you change DCViewModel
's value, the wrapped value's setter will not be called and @Published
won't publish messages.
SwiftUI - changes in nested View Model classes not detected using onChange method
Figure it out. Just had to create another AnyCancellable
variable to call objectWillChange
publisher.
WatchDayProgramViewModel
class WatchDayProgramViewModel: ObservableObject {
@Published var workoutModel = WorkoutModel()
var cancellable: AnyCancellable?
init() {
cancellable = workoutModel.objectWillChange
.sink { _ in
self.objectWillChange.send()
}
}
}
While I have provided my answer, that worksaround with viewmodels, I would love to see/get advice on other alternatives.
SwiftUI - Change an @Published var from one view and have it reflect on another
If ExerciseSelector and its array is your "single source of truth" then you need to do something like you have already done so that both views can use the same instance. Another option to look into is to use a @EnvironmentObject which is a different way of achieving basically the same. See this article for instance to learn about EnvironmentObject
Dynamically changing colors with @State or @ObservableObject using static functions in Swift
Dynamically changing colors with @State or @ObservableObject using static functions in Swift
Simple answer: this is not possible.
Simple reason: @Published
works only on instance var and not static
As there is missing context I just asume you want to change the colors from different views. If thats the reason for implementing the function as static there is a workaround.
Instantiate your ColorChangingClass
at the top most View that uses it as a @StateObject
. Hand it down to the child views via .environmentObject()
.
If you provide more context there could be other possible solutions too.
Change the @Published object value without triggering the didSet {}?
Why not simply use a custom method where you could selectively do the following functionality using a boolean check. For Example:
func setParameters(_ parameters: [String: String], andLoad load: Bool) {
dicParameters = parameters
if load {
loadDemos()
}
}
variable in observable object not accessible after declaration (SwiftUI)
The problem was, that I instantiated the PostRepository at two different locations. I solved the problem, by declaring a global variable instead.
Related Topics
Swift 3/4 Dash to Camel Case (Snake to Camelcase)
Add a File Generated by Run Script into The Test Target Compilation List in Xcode
Rxswift + Mvvm + Coordinator Pattern, How to Wait for Coordinator Result Sequentially
Swiftui Published Updates Not Refreshing
Macos App Sandboxing - Read Access to Referenced Files from Parsed Xml
Aurendercallbackstruct in Swift
Swift 3: Convert a String to an Array
Images Being Flipped When Adding to Nsattributedstring
Communicate Data Between Watchos & Today Extension Widget
Swift Set UIbutton Setbordercolor in Storyboard
Avaudiopcmbuffer Built Programmatically, Not Playing Back in Stereo
Solve Equations of Type A*X = B Using Dgtsv_ or Sgtsv_
No Trailing Closures Support for Methods with Default Parameter Values
Appdelegate#Applicationdidfinishlaunching Not Called for Swift 4 Macos App Built from Command Line
Custom Markers Disappear on Zoomin The Map and Appear on Zoomout The Map with Clustering
Swift Unsafemutablepointer & Unsafemutablepointer<Unsafepointer<Sometype>>