ios – Swift UI on receive timer causes scroll view bug


Hello I have a basic view in swift ui that uses a timer that executes every second and an on receive method to do something every second. This on receive causes the view’s scroll view to glitch or have a buggy scroll every time it executes. I want to run an action every second only when the specific view is displayed on the screen. Whats an alternative way to do this that won’t mess with the view?

I tried calling a recursive function in the on appear which recalls its self every second using a dispatch queue (interacting with a view-scrolling, messes with a normal timer so I use main dispatch queue), I feel like this isn’t the best approach as it can keep executing even with the view isn’t shown anymore. I tried to only do a recursive call when the scenePhase is active and the view is displayed (bool flag set on appear/disappear) but sometimes it still executes when the view isn’t shown.

EnvironmentObject var viewModel: MessageViewModel

//timer and on receive
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

.onReceive(timer) { _ in
            if appeared && scenePhase == .active {
                viewModel.timeRemaining -= 1
                if viewModel.timeRemaining == 0 {
                    viewModel.getMessagesNew()
                    viewModel.timeRemaining = 5.0
                }
            }
        }

//recursive func
func runActionEverySecond() {
        let dispatchTime = DispatchTime.now() + 1.0
  
        DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
            print("running=---------------")
            if appeared && scenePhase == .active {
                viewModel.timeRemaining -= 1
                if viewModel.timeRemaining == 0 {
                    viewModel.getMessagesNew()
                    viewModel.timeRemaining = 5.0
                }
                runActionEverySecond()
            }
        }
    }

class MessageViewModel: Identifiable, ObservableObject {
      @Published var timeRemaining = 7.0
    func getMessagesNew(){
        guard let myUID = Auth.auth().currentUser?.uid else { return }
        if let index = currentChat {
            if let last = chats[index].messages?.first(where: { (chats[index].convo.uid_one == myUID) ? $0.uid_one_did_recieve == true : $0.uid_one_did_recieve == false } )?.timestamp {
                service.getMessagesNew(docID: chats[index].convo.id ?? "", lastdoc: last) { messages in
                    var new = [Message]()
                    if self.chats[index].convo.uid_one == myUID {
                        new = messages.filter({ $0.uid_one_did_recieve == true })
                    } else {
                        new = messages.filter({ $0.uid_one_did_recieve == false })
                    }
                    if !new.isEmpty {
                        for i in 0..<new.count {
                            if let text = new[i].text {
                                if let decrypted_text = self.decrypt(text: text, key: self.chats[index].user.publicKey){
                                    new[i].text = decrypted_text
                                }
                            }
                        }
                        if let mess = self.chats[index].messages {
                            let newMessages = new.filter { message in
                                !mess.contains(where: { $0.id == message.id })
                            }
                            self.chats[index].messages = newMessages + mess
                            self.chats[index].lastM = newMessages.first
                        } else {
                            self.chats[index].messages = new
                            self.chats[index].lastM = new.first
                        }
                        self.setDate()
                    } else {
                        self.timeRemaining += 8
                    }
                }
            } else if let last = chats[index].messages?.first?.timestamp {
                service.getMessagesNew(docID: chats[index].convo.id ?? "", lastdoc: last) { messages in
                    var new = [Message]()
                    if self.chats[index].convo.uid_one == myUID {
                        new = messages.filter({ $0.uid_one_did_recieve == true })
                    } else {
                        new = messages.filter({ $0.uid_one_did_recieve == false })
                    }
                    if !new.isEmpty {
                        for i in 0..<new.count {
                            if let text = new[i].text {
                                if let decrypted_text = self.decrypt(text: text, key: self.chats[index].user.publicKey){
                                    new[i].text = decrypted_text
                                }
                            }
                        }
                        if let mess = self.chats[index].messages {
                            let newMessages = new.filter { message in
                                !mess.contains(where: { $0.id == message.id })
                            }
                            self.chats[index].messages = newMessages + mess
                            self.chats[index].lastM = newMessages.first
                        } else {
                            self.chats[index].messages = new
                            self.chats[index].lastM = new.first
                        }
                        self.setDate()
                    } else {
                        self.timeRemaining += 12
                    }
                }
            }
        }
    }
}

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img