SwiftUI updating UI with high frequency data

守給你的承諾、 提交于 2021-02-08 06:51:21

问题


I'm trying to update the main view with high frequency data coming from separate background thread. I've created two tabviews and in case of slow update rate I can change the view. But in another case the UI doesn't react. I've observed this behavior only on real device, in the simulator works everything fine.

The while loop is still representing an imu, just to keep it simple.

Did someone any idea how to fix this issue?

Many thanks!

import SwiftUI

struct ContentView: View {
    
    @EnvironmentObject var loop : Loop
    
    var body: some View {
        
        TabView{
        
            VStack {
                Text("Content View")
                LoopView()
            }.tabItem{
                  VStack{
                      Text("tab1")
                      Image(systemName: "car")
                }
                
            }
            
            Text("second view").tabItem{
                                    VStack{
                                        Text("tab2")
                                        Image(systemName: "star")
                }
            }
        }
    }
}


class Loop : ObservableObject {
    
    @Published var i : Int
    
    func startLoop() {
        while true {
            print("i = \(self.i)")
            DispatchQueue.main.async {
                self.i += 1
            }

            //sleep(1) // comment out to simulate worst case
        }
    }
    
    init() {
        DispatchQueue.global(qos: .background).async {
            self.startLoop()
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

回答1:


You need to separate updating storage of frequency data from represented UI part, so storage receives/contains actual real data, but UI part update as soon as you only want (0.5 sec, 1 sec, 5 secs, etc.)

Here is possible approach. Tested with Xcode 12 / iOS 14.

import Combine
class Loop : ObservableObject {
    private var storage: Int = 0
    private var counter = PassthroughSubject<Int, Never>()

    @Published var i : Int = 0   // only for UI

    func startLoop() {
        while true {
            storage += 1     // update storage 
            counter.send(storage) // publish event
        }
    }

    private var subscriber: AnyCancellable?
    init() {
        subscriber = counter
            .throttle(for: 0.5, scheduler: DispatchQueue.global(qos: .background), latest: true) // drop in background
            .receive(on: DispatchQueue.main)  // only latest result
            .sink { [weak self] (value) in    // on @pawello2222 comment
               self?.i = value
            }

        DispatchQueue.global(qos: .background).async {
            self.startLoop()
        }
    }
}



回答2:


Have you tried solving that problem by using combine? If your ui is updating too fast you can for example collect some data in combine in a kind of buffer and then after the buffer is full you can push it to your view. Another approach would be to debounce the input for a specific delay and then push only the last update to your view. For example lets say you have your published variable i that constantly updates it value. You could introduce the following viewmodel:

class Loop: ObservableObject {
    @Published var i: Int = 0
    @Published var updatedVariable: Int = 0
    private var bag = Set<AnyCancellable>()

    init() {
        $i
          .debounce(for: 0.5, scheduler: DispatchQueue.main)
          .sink { [weak self] value in 
              self?.updatedVariable = value
          }
          .store(in: &bag)
        startLoop()
    }

    func startLoop() {
        while true {
            print("i = \(self.i)")
            DispatchQueue.main.async {
                self.i += 1
            }
        }
    }
}

This way you update your ui only every 0.5 seconds if you use the updatedVariable instead the i variable.



来源:https://stackoverflow.com/questions/63678438/swiftui-updating-ui-with-high-frequency-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!