You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中@Published修饰的UIImage属性未触发视图更新,MJPEG流无法显示

问题原因
  1. 核心错误:CameraView 中使用 @ObservedObject 修饰并在视图内部初始化 CameraViewModel,不符合属性包装器的使用规范。@ObservedObject 不负责管理实例生命周期,SwiftUI 视图重绘时会反复重建 CameraViewModel 实例,导致新接收的图片赋值给了已销毁的旧实例,视图绑定的新实例始终保留默认值。
  2. 逻辑错误:onAppear 修饰符错误挂载在 Button 组件上,仅当 Button 渲染时才会触发流加载方法,逻辑不符合预期。
  3. 潜在问题:当前 MJPEG 流解析逻辑仅在收到响应头时拼接生成图片,不符合 MJPEG 按 boundary 分隔帧的标准规范,大概率会出现丢帧、图片解析失败的问题。
解决方案

1. 修正 ViewModel 属性包装器

将视图内部初始化的 @ObservedObject 替换为 @StateObject,@StateObject 是 SwiftUI 专门用于在视图内部初始化并持有 ObservableObject 生命周期的属性包装器,不会随视图重绘被销毁:

// 替换前
@ObservedObject var cameraViewModel: CameraViewModel = CameraViewModel()
// 替换后
@StateObject var cameraViewModel: CameraViewModel = CameraViewModel()

如果 CameraViewModel 是从上层视图传入的,则不需要在当前视图初始化,直接声明为 @ObservedObject var cameraViewModel: CameraViewModel 即可,由上层视图负责实例的生命周期管理。

2. 调整 onAppear 挂载位置

将 onAppear 修饰符挂载到外层容器视图上,保证页面加载时就触发流加载逻辑:

struct CameraView: View {
    @Binding var showCamera: Bool
    @StateObject var cameraViewModel: CameraViewModel = CameraViewModel()
    var body: some View {
        VStack {
            Image(uiImage: cameraViewModel.cameraImage!)
                .aspectRatio(contentMode: .fit)
                .frame(height: 200)
            
            Button("Close") {
                cameraViewModel.stop()
                showCamera.toggle()
            }
        }
        .onAppear { // 移到VStack层级上
            cameraViewModel.play()
        }
    }
}

3. 可选优化项

  • MJPEG 解析逻辑优化:先从响应头的 Content-Type 字段获取 boundary 标识,按 boundary 拆分收到的数据流,拿到完整的单帧数据后再转换为 UIImage,避免无效解析。
  • 空值容错处理:去掉 cameraImage 的强制解包,避免空值崩溃:
// CameraViewModel 中定义
@Published var cameraImage: UIImage? = UIImage(systemName: "cloud.heavyrain.fill")

// CameraView 中渲染
if let image = cameraViewModel.cameraImage {
    Image(uiImage: image)
        .aspectRatio(contentMode: .fit)
        .frame(height: 200)
} else {
    ProgressView()
}

内容的提问来源于stack exchange,提问作者esbenr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 15:24:02