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
}
}
}
}
}
}