kang
kang

Reputation: 79

SwiftUI ObservedObject not updating in View

class Room: ObservableObject { ... }

Contact: ObservableObject {
    var chatRoom: Room
}

class Account: ObservableObject {

    var rooms: Room { … }

    var contacts: [Contact] {
        return rooms.map {
            Contact(chatRoom: $0)
        }
     }

    func listenForRoomEvents() {
        // Called on instantiation of a Room, this fires self.objectWillChange on room updates and is working properly
    }
}

struct RoomView: View {
    @ObservedObject var room: Room
}

/ THIS IS WORKING /

struct ParentView: View {
    @EnvironmentObject account: Account

    var body: some View {
        RoomsView(account.rooms)
        .onAppear {
            self.account.listenForRoomEvents()
        }
    }
}

struct RoomsView: View {
    var rooms: [Room]

    var body: some View {
        ForEach(rooms) { room in
            NavigationLink(destination: RoomView(room: room)) {
                RoomListItemView(room: room)
            }
        }
    }
}

/ THIS IS NOT WORKING /

struct ParentView: View {
    @EnvironmentObject account: Account

    var body: some View {
        Child1(contacts: account.contacts)
        .onAppear {
            self.account.listenForRoomEvents()
        }
    }
}

struct Child1: View {
    @State var selectedContact: Contact?
    var contacts: [Contact]
    
    var body: some View {
        RoomView(selectedContact.chatRoom)

        UserSelectorView(contacts: contacts, selectedUser: $selectedContact) // View allowing selection of a user
    }
}

I outlined my setup above; basically, I am instantiating a RoomView object with a Room instance containing all the chat events and other details. Child1 holds a selected contact state variable which is bound to two of its own subviews, one of which allows for the user to select a different contact and such.

What does not make sense to me is that the RoomView renders just fine with all it's events, but in the second solution I have it does not update when new messages come in or when one should be displayed after sending, for instance. I am passing a reference to the same Room object to it, but cannot for the life of me get it to update properly like it does in the first solution.

When I select a new user and go back to the previous one, the messages are all updated as expected.

Here is what I have tried so far:

Upvotes: 0

Views: 439

Answers (2)

kang
kang

Reputation: 79

Okay I finally figured this out, I have no idea why this works and it might be a dumb solution; I needed to not only pass the selectedContact as a parameter, but also the room as another parameter. The code in the outline isnt exactly as it is in my source, but if you ever run into a problem where a class variable isnt updating properly in a view try to pass the variable down from higher up in the chain.

Upvotes: 1

Satoshi Nakajima
Satoshi Nakajima

Reputation: 2143

Which version of Xcode are you running? If you are running Xcode 12.2 beta2, I'd recommend you to try it with Xcode 12.0.

I saw a similar issue with my code. After wasting a lot of hours, I finally figure it out that Xcode (I was runnig Xcode 12.2 beta2) has a bug.

SwiftUI: Updating an array item does not update the child UI immediately

Upvotes: 0

Related Questions