Swift UI 被高频 @StateObject 更新淹没了吗?

2024-02-09

Scenario

一个简单的 SwiftUIApp由一个TabView有两个选项卡。这App结构体有一个@StateObject属性,该属性正在重复且非常快速地(每秒 30 次)更新simulateFastStateUpdate.

在这个例子中,simulateFastStateUpdate没有做任何有用的工作,但它非常类似于快速更新应用程序状态的真实函数。该函数在短时间内在后台队列上执行一些工作,然后在主队列上安排状态更新。例如,当使用相机 API 时,应用程序可能会以每秒 30 次的频率更新预览图像。

Question

当应用程序运行时,TabView不响应点击。它永久卡在第一个选项卡上。去除liveController.message = "Nice"线解决了这个问题。

  1. Why is TabView stuck?
  2. 为什么要更新@StateObject导致这个问题?
  3. 如何调整这个简单的例子,以便TabView是不是卡住了?
import SwiftUI

class LiveController: ObservableObject {
    @Published var message = "Hello"
}

@main
struct LiveApp: App {
    @StateObject var liveController = LiveController()

    var body: some Scene {
        WindowGroup {
            TabView() {
                Text(liveController.message)
                    .tabItem {
                        Image(systemName: "1.circle")
                    }
                Text("Tab 2")
                    .tabItem {
                        Image(systemName: "2.circle")
                    }
            }
            .onAppear {
                DispatchQueue.global(qos: .userInitiated).async {
                    simulateFastStateUpdate()
                }
            }
        }
    }
    
    func simulateFastStateUpdate() {
        DispatchQueue.main.async {
            liveController.message = "Nice"
        }
        
        // waits 33 ms ~ 30 updates per second
        usleep(33 * 1000)
        
        DispatchQueue.global(qos: .userInitiated).async {
            simulateFastStateUpdate()
        }
    }
}

您正在通过这些不断的更新阻塞主线程,并且应用程序正忙于处理您的 UI 更新并且无法处理触摸输入(也在主线程上接收)。

任何创建这种快速事件流的东西都需要被限制。您可以使用组合的throttle or debounce减少 UI 更新频率的功能。

看这个示例,我添加了课程UpdateEmittingComponent生成更新Timer。这可能是您的后台组件正在快速更新。

In your LiveController我正在观察组合的结果。我在那里添加了一个throttle进入管道,这将导致message发布者通过删除所有中间值每秒触发一次。

删除throttle最终会出现无响应的情况TabView.

import SwiftUI
import Combine

/// class simulating a component emitting constant events
class UpdateEmittingComponent: ObservableObject {
    @Published var result: String = ""
    
    private var cancellable: AnyCancellable?
    
    init() {
        cancellable = Timer
            .publish(every: 0.00001, on: .main, in: .default)
            .autoconnect()
            .sink {
                [weak self] _ in
                self?.result = "\(Date().timeIntervalSince1970)"
            }
    }
}

class LiveController: ObservableObject {
    @Published var message = "Hello"
    
    @ObservedObject var updateEmitter = UpdateEmittingComponent()
    private var cancellable: AnyCancellable?
    
    init() {
        updateEmitter
            .$result
            .throttle(for: .seconds(1),
                scheduler: RunLoop.main,
                latest: true
            )
            .assign(to: &$message)
    }
}

@main
struct LiveApp: App {
    @StateObject var liveController = LiveController()

    var body: some Scene {
        WindowGroup {
            TabView() {
                Text(liveController.message)
                    .tabItem {
                        Image(systemName: "1.circle")
                    }
                Text("Tab 2")
                    .tabItem {
                        Image(systemName: "2.circle")
                    }
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift UI 被高频 @StateObject 更新淹没了吗? 的相关文章

  • ios 8 核心数据崩溃

    保存时 CoreData 发生崩溃 2014 09 16 09 51 58 273 My app 2678 105246 Terminating app due to uncaught exception NSInvalidArgument
  • 在 Swift 3 中单击和双击 UITableViewCell

    我在 TableView Cell 上有故事板 segue 我用它来在单元格单击中传输到另一个 VCdidSelectRowAt方法 现在我双击了TapGestureRecognizer处理手机上的点击问题 问题是 单击时 segue 正在
  • 应用程序图标未刷新

    我更改了新版本应用程序中的图标图像 并且我在设备中安装了旧版本应用程序 然后我安装了新版本 它在 iOS 5 中运行良好 但在 iOS 6 中 图标没有刷新 它仍然显示旧版本图标 徽标 如果没有安装旧版本应用程序 该设备在 iOS 5 和
  • 自动调整大小完成后如何获取帧大小

    我想知道 如何以及何时 viewDidLoad viewWillAppear viewDidAppear 可以获得自动调整大小以适合其父视图的 UIViews 框架大小 从你的问题中不清楚你为什么想要它 但我想这是为了布局你的子视图 幸运的
  • Swift 数组设置索引值不起作用

    我有一个方法 下面的内容 其中queue2只是一个 Int 我打印了很多东西 看看一切是否都正常 public func cool item Int println item println back queue2 insert item
  • 使用 UIActionSheet 更改视图时工具栏项目消失

    当从 a 启动视图时UIActionSheet按钮 通过导航栏后退按钮返回视图后 工具栏虽然仍然可见 但上面没有任何以前的按钮 自从更新到 iOS 6 以来 这个错误就出现了 并且是在模拟器和仅运行 iOS 6 的设备上测试时发生的 如果我
  • 如何在我的 iOS 项目中添加和执行 .sql 文件?

    我找到了很多关于在 iOS 中使用 SQLite 数据库的教程 但没有找到任何直接引用 sql 文件的内容 谁能告诉我如何将现有的 SQL 数据库链接到我的应用程序 编辑 这是一个 MySQL 转储 我们有一个基于浏览器的抽认卡程序 现在我
  • iOS:从非图像数据生成图像(Godus,如风景)

    所以看到图像后Godus http www kickstarter com projects 22cans project godus我想知道如何生成简单的 非交互式的 2D 图像 with 不同高度或层数的颜色不同就像下面的图片一样 我只
  • iOS 外部附件框架:如何获取特定 MFI 设备的协议字符串

    我正在编写一个 iOS 应用程序 用于与 mini mPlay Drumi MP18B 小型蓝牙扬声器 进行通信 据我所知 showBluetoothAccessoryPickerWithNameFilter仅显示协议字符串添加到 Info
  • 在 Interface Builder 中的资产目录上使用图像

    是否可以直接在界面生成器上使用添加到资产目录中的图像 这是怎么做到的 在 UIImageView 属性上 我看不到任何引用资产目录上任何图像的选项 Import the images into the xcassets folder 单击右
  • Swift 对异步编程有什么语言级别的支持(如果有)?

    当应用程序必须通过不可预测的网络 例如智能手机应用程序 进行通信时 异步编程对于响应式用户界面来说是必须的 用户界面必须保持响应 同时等待结果从互联网上某处的服务器返回 在大多数语言中 应用程序程序员必须实现自己的状态机 可能使用闭包 来响
  • Swift:从自定义 UITableViewCell 中的 UITextField 检索文本并将其放入数组中

    我正在制作一个非常简单的应用程序 用户在第一个屏幕中输入人数 在第二个屏幕中 它会生成一些UITableViewCell基于用户在第一个屏幕中输入的数字 这UITableViewCell have a UITextField在其中 一旦用户
  • 切换到工作区并在 Xcode 中添加 CocoaPods 后提交 git 吗?

    我刚刚在 Xcode 5 中将 CocoaPods 添加到我当前的项目中 当然 CocoaPods 创建了一个工作区 并且我已在 Xcode 中启动了该工作区 我在工作区中看到了我的项目和 Pods 项目 我的项目从第一天起就处于源代码控制
  • iOS 中的等宽字体是什么?

    我想要在我的 iOS 应用程序中为 UILabel 使用等宽字体 不幸的是 我找不到一个 甚至 美国打字机 实际上也不是等宽的 XCode 中可用的等宽字体是什么 iOS 等宽字体 Courier Courier Bold Courier
  • 从 RemoteIO 保存音频的示例?

    我进行了搜索 但没有找到任何从 RemoteIO 音频单元保存音频的好示例或教程 我的设置 使用 MusicPlayer API 我有几个 AUSamplers gt MixerUnit gt RemoteIO 音频播放效果很好 我想添加将
  • 如何将十六进制数组转换为 UIImage?

    有几个与使用 P25mi 动态打印图像相关的未解答问题 没有一个得到公认的答案 下面有几个链接 如何将图像转换为位图代码以便在 iPhone 中进行蓝牙打印 https stackoverflow com questions 1383828
  • swift 中的负数模

    负数模如何在 swift 中工作 当我执行 1 3 时 它给出 1 但余数是 2 其中有什么问题 雨燕余数运算符 计算余数 整数除法 a b a a b b where 是截断整数除法 在你的情况下 1 3 1 1 3 3 1 0 3 1
  • Cognito/IAM 策略和 S3 获取对象

    我正在尝试将 S3 和 Cognito 集成到我的 iOS 应用程序中 但到目前为止尚未成功 我相信该错误与我针对 Auth 和 Unauth 用户的 IAM 策略有关 所以这是我的政策 Version 2012 10 17 Stateme
  • 应用未能及时恢复

    我在一个非常具体的场景中遇到 未能及时恢复 崩溃 我认为与看门狗相关 仅在从后台恢复时 并且仅在进入后台后在很短的时间内执行此操作 a最多几秒钟 这似乎是相关的崩溃日志 Incident Identifier E30F2238 5B15 4
  • 如何在 Swift 语言中传递错误指针?

    我试图在 swift 中传递错误指针 但无法这样做 编译器抱怨 NSError 无法转换为 NSErrorPointer var error NSError NSError var results context executeFetchR

随机推荐