SwiftUI使用高频数据更新UI



我正试图用来自独立后台线程的高频数据更新主视图。我已经创建了两个选项卡视图,如果更新速度较慢,我可以更改视图。但在另一种情况下,UI没有反应。我只在真实的设备上观察到了这种行为,在模拟器中一切都很好。

while循环仍然表示一个imu,只是为了保持简单。

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

非常感谢!

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秒等(

这是一种可能的方法。使用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()
}
}
}

您是否尝试过使用组合来解决该问题?如果你的ui更新太快,你可以在一种缓冲区中收集一些数据,然后在缓冲区满了之后,你可以把它推送到你的视图中。另一种方法是对特定延迟的输入进行去抖动,然后只将最后一次更新推送到您的视图中。例如,假设您有一个已发布的变量i,它会不断更新它的值。您可以引入以下视图模型:

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

这样,如果使用updatedVariable而不是i变量,则每0.5秒更新一次ui。

相关内容

  • 没有找到相关文章

最新更新