I have a list in a view (lets call it view A) where I push a view B via NavigationLink from view A and manipulate the CurrentSubjectValue to the initial view A. The moment the data is added and the didChangd.send(value) is dispatched to view A I get a warning that updating a cell that does not belong to a view. It seems that view A is removed from window which is unintuitive based on my previous UINavigationController behavior. Any idea?
View A (MainView)
struct MainView: View {
@ObjectBinding var currentProfileIdStore = CurrentProfileIdStore.shared
var body: some View {
NavigationView {
if (currentProfileIdStore.didChange.value == nil) {
NavigationLink(destination: ProfilesView()){ Text("show profiles view")}
} else {
List {
Section {
ForEach(0..<1) { _ in
PresentationLink(destination: ProfilesView()) {
Text("Profiles")
}
}
}
Section {
ForEach(0..<1) { _ in
Text("Items")
}
}
}.listStyle(.grouped)
}
}.navigationBarTitle(currentProfileIdStore.didChange.value ?? "unknown")
}
}
Then profiles view is presented
struct ProfilesView : View {
@ObjectBinding var profileManager = CurrentProfileIdStore.shared
@ObjectBinding var profileProvider = ProfileProvider.shared
var body: some View {
NavigationView {
List {
Section {
ForEach(0..<1) { _ in
NavigationLink(destination: NewProfile()) {
Text("Add Profile")
}
}
}
Section {
ForEach(self.profileProvider.didChange.value) { profile in
VStack {
if profile.id == self.profileManager.didChange.value {
Image(systemName: "g.circle").transition(.move(edge: .top))
}
ProfileCellView(profile: profile)
Text(self.profileManager.didChange.value ?? "unknown").font(.footnote).color(.secondary)
}
}
}
}
.navigationBarTitle("Profiles")
.listStyle(.grouped)
}
}
}
and then we could add a new profile
struct NewProfile: View {
@State var name: String = ""
@State var successfullyAdded: Bool = false
@ObjectBinding var keyboardStatus = KeyboardStatus()
var profileProvider = ProfileProvider.shared
var body: some View {
NavigationView {
VStack {
if self.successfullyAdded {
Text("Successfully added please go back manually :)").lineLimit(nil)
}
Form {
Section(header: Text("Enter name")) {
TextField("Enter your name", text: $name)
}
}
if name.count > 3 {
Button(action: {
self.profileProvider.addProfile(new: Profile(name: self.name, id: UUID().uuidString)) {
assert(Thread.isMainThread)
self.successfullyAdded = true
}
}) {
Text("Add")
}.transition(.move(edge: .bottom))
}
}.padding(.bottom, self.keyboardStatus.didChange.value)
}.navigationBarTitle("Add Profile")
}
}
and then there is provider
class ProfileProvider: BindableObject {
enum Query {
case all
var filter: (Profile) -> Bool {
switch self {
case .all:
return { p in true }
}
}
}
static var samples: [Profile] = []
static var shared: ProfileProvider = {
return ProfileProvider(query: .all)
}()
var didChange = CurrentValueSubject<[Profile], Never>([])
private var query: Query?
private init(query: Query? = nil) {
self.query = query
assert(Thread.isMainThread)
dispatchDidChange()
}
func dispatchDidChange() {
assert(Thread.isMainThread)
if let valid = self.query {
didChange.send(ProfileProvider.samples.filter { valid.filter($0) })
} else {
didChange.send([])
}
}
func addProfile(new: Profile, comp: () -> Void) {
ProfileProvider.samples.append(new)
comp()
dispatchDidChange()
}
keep in mind that multiple views share the same provider subject. so the issue happens when the new profile is added.
self.profileProvider.addProfile(new
there are two more issues, one that when back in mainView the button no longer works. Also when modally presented I don't yet know how to go back manually.
SwiftUI
is barely in beta 3 of version 1! I get those warnings too. Hopefully, this will be improved in future betas. (1) To turn off these warnings, setOS_ACTIVITY_MODE
todisable
in your builds. Not necessarily recommending that - but it does get rid of noise. (2) If the behavior is not what you'd expect, post some code. So we can help.NavigationLink
for adding a new profile in aForEach
for no reason at all. Whats more, the object you give theForEach
is notIdentifiable
. Which means that when your data changes the old NavigationLink shouldn't exist. Remove theForEach
it does nothing since it goes through0..1
(one index). I don't know if this solves your problem but its useless code.. so remove it.