Home > Net >  refreshing a View below onOpenURL
refreshing a View below onOpenURL

Time:03-01

I'm making a chat-like application with a main view called ChatView and a list of Conversation Views with different contacts. The idea behind the app is that messages are split into 3 parts and sent in a form of hyperlinks. The person receiving the message clicks the link and is presented with a sheet with a list of contacts in the app. When choosing a contact, the message is added to Core Data. I registered an onOpenURL handler on ChatView:

            ChatView()
                .environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
                .onOpenURL { url in
                    acceptedURL = .init(id: .init(), url: url)
                }
                .sheet(item: $acceptedURL) { link in
                    MessageDecryptView(url: link.url)
                }
        }

Inside MessageDecryptView I do some processing and add the message to Core Data.

The issue I have is that if the app is displaying a conversation with specific user and a hyperlink is opened adding the message to that same conversation, the conversation is not updated when the sheet dismisses. Instead the user has to go back to ChatView and enter the ConversationView again which fetches the messages from Core Data onAppear.

So for the scenario of MessageDecryptView sheet being opened on top of ConversationView I am looking for one of two possible solutions:

  1. how to go back to ChatView
  2. (prererable) How to update the displayed ConversationView with a message that was just added

I would appreciate any help!

EDIT My app is written in SwiftUI. I have ViewModel classes that are used by my views for interacting with Core Data. Inside ConversationView there is

@ObservedObject private var messageVM = MessageViewModel()

and then the following is how I fetch the data from the database:

.onAppear(perform: {
            userVM.getCurrentUser()
            messageVM.getConversation(with: user.id!)
        })

CodePudding user response:

You have to notify your view(s) that something changed in the messages. So just before - or inside of

 MessageDecryptView(url: link.url)

insert

MessagesClass.objectWillChange.send()

and replace MessagesClasswith the name of your NSManagedObject class in CoreData that contains your messages – the one that is used to display the messages in the view.

CodePudding user response:

We don't use view model objects in SwiftUI, we use property wrappers that make the View data struct behave like an object. And the one for core data object is @ObservedObject so body is called when the object changes, so replace:

.onAppear(perform: {
            userVM.getCurrentUser()
            messageVM.getConversation(with: user.id!)
        })

with

@ObservedObject var user: User

and

ChatView(user: user)

Then for fetching we use @FetchRequest and body is called when any of the objects change or an object is inserted, moved or deleted. So in your case it would look something like this:

@FetchRequest var conversations: FetchedResults<Conversation>

    init(user: User) {
        let sortDescriptors = [SortDescriptor(\Conversation.timestamp, order: sortAscending ? .forward : .reverse)]
        _conversations = FetchRequest(sortDescriptors: sortDescriptors, predicate: NSPredicate(format: "user = %@", user), animation: .default)

Alternatively you can pass in a FetchRequest to your View init if that is simpler:

ConversationsView(conversations: FetchRequest(...

You can also make an extension on your entity types to return pre-configured NSFetchRequests that can be used to easily create FetchRequest structs, e.g.

extension Item {
    static func myFetchRequest() -> NSFetchRequest<Item> {
        let fr = Self.fetchRequest()
        fr.propertiesToFetch = ["title"]
        fr.sortDescriptors = [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)]
        return fr
    }
}


@FetchRequest(
    fetchRequest: Item.myFetchRequest(),
    animation: .default)
private var items: FetchedResults<Item>
  • Related