SwiftUI:App回到前台后外接屏幕视图无法更新
问题描述
我开发了一款和弦与歌词应用,需要通过外接屏幕实现歌词投影功能。App在切换至后台再返回前台前运行正常,但返回后外接屏幕的视图不再更新——仅初始显示时数值正确,后续完全无变化。
Info.plist 配置
EnableMultipleWindows = YES- 场景配置(SceneConfiguration):
- 角色:External Display Session Role Non-Interactive
- 配置名称:External
- 代理类名:
$(PRODUCT_NAME).ExternalSceneDelegate
外接屏幕测试视图代码
struct ExternalScreenTestView: View { @ObservedObject var counter = TestCounter.shared var body: some View { Text(counter.count.description) .font(.system(size: 50)) } } class TestCounter: ObservableObject { private var timer: Timer? @Published var count = 1 static var shared:TestCounter = TestCounter() init() { self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.count += 1 } } }
ExternalSceneDelegate 代码
final class ExternalSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var controller: UIHostingController<ExternalScreenTestView>? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let content = ExternalScreenTestView() window = UIWindow(windowScene: scene) controller = UIHostingController(rootView: content) window?.rootViewController = controller window?.isHidden = false } }
解决方案
1. 确保@Published属性在主线程更新
定时器闭包默认运行在非主线程,直接更新@Published属性无法触发UI刷新。修改TestCounter的定时器逻辑,将属性更新操作切换到主线程:
class TestCounter: ObservableObject { private var timer: Timer? @Published var count = 1 static var shared: TestCounter = TestCounter() init() { self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in DispatchQueue.main.async { self?.count += 1 } } } }
2. 处理外部场景的激活事件
App从后台返回时,外部场景可能需要重新绑定视图以恢复订阅。修改ExternalSceneDelegate,添加场景激活时的视图重置逻辑:
final class ExternalSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var controller: UIHostingController<ExternalScreenTestView>? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } setupExternalWindow(for: scene) } func sceneDidBecomeActive(_ scene: UIScene) { guard let scene = scene as? UIWindowScene else { return } setupExternalWindow(for: scene) } private func setupExternalWindow(for scene: UIWindowScene) { let contentView = ExternalScreenTestView() window = UIWindow(windowScene: scene) controller = UIHostingController(rootView: contentView) window?.rootViewController = controller window?.isHidden = false } }
3. 优化视图的ObservableObject绑定
如果不需要跨场景共享计数器实例,建议将视图中的@ObservedObject替换为@StateObject,它能更稳定地管理对象生命周期:
struct ExternalScreenTestView: View { @StateObject var counter = TestCounter() var body: some View { Text(counter.count.description) .font(.system(size: 50)) } }
若必须保持单例共享,保留@ObservedObject var counter = TestCounter.shared即可。
内容的提问来源于stack exchange,提问作者MarekP
相关产品推荐
相关产品推荐

