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

SwiftUI自定义相机切换Tab加载缓慢,如何优化性能?

解决Tab切换到自定义相机视图耗时过长的问题

问题根源

每次切换到Camera Tab时,PhotoView会被重新初始化,连带CameraModel也会重建,而AVCaptureSession的配置、权限检查和启动是耗时操作,重复执行就会导致延迟。另外当前拍照逻辑里会停止session,切换回来又要重新启动,进一步加剧了等待时间。


解决方案

1. 保持CameraModel的生命周期(核心优化)

把CameraModel实例提升到父视图ContentView中,避免每次切换Tab都销毁重建模型:

修改ContentView:

struct ContentView: View {
    @State private var selectedTab: Tab = .Home
    // 将CameraModel提升到父视图,维持全局生命周期
    @StateObject private var cameraModel = CameraModel()

    var body: some View {
        VStack(spacing: 0) {
            switch selectedTab {
                case .Camera:
                    // 传入已创建的相机模型
                    PhotoView(camera: cameraModel)
                        .transition(.identity)
                case .Records:
                    Color.gray
                        .transition(.identity)
                case .Home:
                    HomeView()
                        .transition(.identity)
                case .Test:
                    Color.cyan
                        .transition(.identity)
                case .Settings:
                    SettingsView()
                        .transition(.identity)
            }
            
            CustomTabBar(selectedTab: $selectedTab)
        }
    }
}

修改PhotoView,接收外部传入的模型:

struct PhotoView: View {
    @ObservedObject var camera: CameraModel
    
    var body: some View {
        ZStack {
            // 原有视图布局代码保持不变
            GeometryReader { proxy in
                let size = proxy.size
                CameraPreview(camera: camera, size: size)
            }
            
            VStack {
                // 原有按钮逻辑保持不变
            }
        }
        .onAppear {
            // 仅当session未运行时才启动,避免重复执行初始化
            if !camera.session.isRunning {
                camera.Check()
            }
        }
    }
}

2. 优化Session的启停逻辑

当前takePic方法里会延迟停止session,导致切换回来需要重新启动。修改逻辑,让session保持运行状态:

修改CameraModel的takePic方法:

func takePic() {
    DispatchQueue.global(qos: .background).async {
        self.output.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
        
        DispatchQueue.main.async {
            withAnimation {
                self.isTaken.toggle()
            }
        }
    }
    
    // 移除这行代码,不要停止session
    // DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
    //   self.session.stopRunning()
    // }
}

修改reTake方法,无需重新启动session:

func reTake() {
    DispatchQueue.main.async {
        withAnimation {
            self.isTaken.toggle()
        }
        self.isSaved = false
    }
    // 移除session.startRunning(),因为session一直处于运行状态
}

3. 预加载相机资源(可选)

如果希望第一次切换到相机Tab时完全无延迟,可以在App启动时提前初始化相机:

在ContentView中添加:

struct ContentView: View {
    // ... 原有代码
    var body: some View {
        VStack(spacing: 0) {
            // ... 原有代码
        }
        .onAppear {
            // 提前检查权限并配置session
            cameraModel.Check()
        }
    }
}

4. 优化预览层适配

修改CameraPreview,确保预览层能正确适配视图大小变化,同时避免重复启动session:

struct CameraPreview: UIViewRepresentable {
    @ObservedObject var camera: CameraModel
    var size: CGSize

    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        
        camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
        camera.preview.videoGravity = .resizeAspectFill
        view.layer.addSublayer(camera.preview)
        
        // 仅在session未运行时启动
        if !camera.session.isRunning {
            camera.session.startRunning()
        }
        
        return view
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        // 更新预览层frame,适配视图尺寸变化
        camera.preview.frame = uiView.bounds
    }
}

优化效果

  • 相机模型仅初始化一次,避免重复执行耗时的AVCaptureSession配置
  • session保持运行状态,切换Tab时无需重新启动
  • 提前预加载资源,消除第一次切换的等待延迟

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:47:35