SwiftUI使用高频数据更新UI [英] SwiftUI updating UI with high frequency data

查看:73
本文介绍了SwiftUI使用高频数据更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用来自单独的后台线程的高频数据更新主视图.我创建了两个tabview,并且在更新速度较慢的情况下,可以更改视图.但是在另一种情况下,UI不响应.我只在真实设备上观察到了这种行为,在模拟器中一切正常.

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.

while循环仍然代表一个imu,只是为了使其简单.

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

有人知道如何解决此问题吗?

Did someone any idea how to fix this issue?

非常感谢!

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

推荐答案

您需要将更新的频率数据存储与表示的UI部件分开,因此存储可以接收/包含实际的真实数据,但是UI部件会在您只需要时立即更新(0.5秒,1秒,5秒等)

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.)

这是可行的方法.在Xcode 12/iOS 14上进行了测试.

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

这篇关于SwiftUI使用高频数据更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆