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

调用proceedToNextScanPass()时ObjectCaptureSession崩溃求助

ObjectCapture API 调用 beginNewScanPass() 频繁崩溃的解决方案

问题概述

开发基于ObjectCapture API的应用时,调用beginNewScanPass()(封装在自定义方法proceedToNextScanPass()中)时频繁崩溃,10次操作中有9次触发崩溃。已参考官方示例实现,但未定位到问题,且该方法无法抛出错误,调试难度大。

核心解决方案

1. 避免ObjectCaptureSession悬垂引用

ObjectCaptureSession是引用类型,若UI持有已被销毁的session实例,调用方法会直接触发崩溃。

  • 修改点:将CapturePrimaryView中直接传递session参数的方式,改为从环境变量AppDataModel中获取,确保UI始终持有有效实例:
    struct CapturePrimaryView: View {
        @Environment(AppDataModel.self) var appModel
        @State private var currentOrbit = 1
        
        // 从appModel中获取session,而非直接传入
        private var session: ObjectCaptureSession? { appModel.objectCaptureSession }
        
        var body: some View {
            ZStack {
                if let session, session.userCompletedScanPass {
                    if currentOrbit <= 2 {
                        Button("Continue") {
                            proceedToNextScanPass()
                        }
                        .buttonStyle(.borderedProminent)
                        .tint(.yellow)
                    } else if currentOrbit == 3 {
                        Button("Finish") {
                            completeCapture()
                        }
                        .buttonStyle(.borderedProminent)
                    }
                } else if let session {
                    ObjectCaptureView(session: session, cameraFeedOverlay: { GradientBackground() })
                        .hideObjectReticle(false)
                        .transition(.opacity)
                }
            }
            .onAppear {
                UIApplication.shared.isIdleTimerDisabled = true
            }
            .onChange(of: session?.state) { _, newValue in
                print("Session State Changed: \(newValue ?? .notSet)")
            }
            .id(session?.id ?? UUID())
        }
        
        // ... 原有proceedToNextScanPass、completeCapture方法
    }
    
  • 同步修改ContentView:移除直接传递session的代码:
    // ContentView中替换原有CapturePrimaryView的调用
    CapturePrimaryView()
        .overlay {
            Spacer()
            if let session = appModel.objectCaptureSession {
                CaptureButton(session: session, hasDetectionFailed: $hasDetectionFailed)
            }
        }
    

2. 严格校验Session状态与忙碌状态

仅判断session.state == .capturing不足以保证操作安全,需同时校验isBusy属性,避免在session处于过渡状态时调用方法:

@MainActor
private func proceedToNextScanPass() {
    guard let session, session.state == .capturing, !session.isBusy else {
        print("无法启动新扫描阶段:当前状态无效。状态:\(session?.state ?? .notSet),是否忙碌:\(session?.isBusy ?? true)")
        return
    }

    session.beginNewScanPass()
    print("新扫描阶段启动成功")
}

3. 同步扫描阶段与本地状态

手动维护currentOrbit易导致与session实际扫描阶段不同步,需通过监听session的scanPassIndex自动更新:

struct CapturePrimaryView: View {
    // ... 原有属性
    
    var body: some View {
        ZStack {
            // ... 原有UI逻辑
        }
        .onChange(of: session?.scanPassIndex) { _, newValue in
            if let newValue {
                currentOrbit = newValue + 1 // scanPassIndex从0开始计数
            }
        }
        // ... 其他修饰符
    }
}

4. 确保所有Session操作在主线程执行

ObjectCaptureSession的所有方法必须在主线程调用,显式标记方法为@MainActor避免线程问题:

@MainActor
private func proceedToNextScanPass() {
    // ... 原有逻辑
}

5. 添加详细日志辅助调试

通过系统日志记录Session状态变化,便于定位崩溃触发时的上下文:

import os.log

private let objectCaptureLogger = OSLog(subsystem: "com.your.app.bundleid", category: "ObjectCapture")

@MainActor
private func proceedToNextScanPass() {
    guard let session, session.state == .capturing, !session.isBusy else {
        os_log("启动扫描阶段失败:状态=%{public}@,忙碌=%{public}d", log: objectCaptureLogger, type: .error, "\(session?.state ?? .notSet)", session?.isBusy ?? true)
        return
    }
    
    os_log("启动第%{public}d次扫描阶段", log: objectCaptureLogger, type: .info, currentOrbit)
    session.beginNewScanPass()
}

额外排查点

  • 检查CaptureFolderManager的目录权限,确保Session能正常读写扫描图片与 checkpoint 文件
  • 在XCode中开启Zombie Objects检测,定位是否存在野指针访问
  • 测试时使用真机(ObjectCapture仅支持真机),避免模拟器环境差异

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:42:01