I tested your code and it has multiple different issues.
Remove
@State from your
CounterLogEntry.
You may want to get
Binding to the properties, we solve it later.
SwiftUI may call
init at any time needed. Unfortunately, this may not make any harm in simple cases, but while developing your app, it would abruptly affect many things and shows unexpected and unpredictable behavior.
Generally, when to create an instance of
@ObservedObject is a very difficult thing to solve. But in your case, you have no need to instantiate it with following the fixes below.
Remove
init from your
CountingView.
Even if your
Player is well-configured as
ObservableObject, SwiftUI cannot observe the changes of its properties when embedded in another object
CountingViewModel.
My recommendation, give up using
CountingViewModel and use
Player directly instead.
You may need some extension for
Player which provides some functionalities of
CountingViewModel.
Code Block | extension Player { |
| func addNewEntry() { |
| counterLog.append(CounterLogEntry()) |
| } |
| |
| func removeEntry(entry: CounterLogEntry) { |
| counterLog.removeAll(where: { e in e.id == entry.id }) |
| } |
| } |
This applies also to the relationship between
Player and
CounterLogEntry.
While
CounterLogEntry is a reference type, any changes for its properties,
title and
count, will not cause updating UI.
My recommendation here, make
CounterLogEntry a struct.
Your
CounterLogEntry would look like as follows:
Code Block | struct CounterLogEntry: Identifiable { //<- Use `struct` |
| let id = UUID() |
| |
| var title = "" //<- Remove `@State` |
| var count = 0 //<- Remove `@State` |
| } |
(As always, you may need some fixes according to this change. I will show you some of them later.)
In my opinion, this is a bug of SwiftUI, but it still exists in Xcode 12, so we need to work with this behavior.
Add
buttonStyle (other than
DefaultButtonStyle) to your buttons.
So, now,
When you use
@ObservedObject, it provides a
Binding generator as a projectedValue.
Your
CountingView would be as follows:
self.$player.counterLog[index].title is a Binding to the
title and you can pass it to
TextField.
There may be some other ways to fix your issues, but I cannot find anything significantly easier. Please try.