# 重新扫描后无法扫描问题修复说明 ## 🚨 问题描述 用户反馈按重新扫描按钮返回扫描后,存在扫描不了的问题。即重新扫描后,相机无法继续检测二维码。 ## 🔍 问题分析 ### 1. **会话状态管理问题** - `metadataOutput` 方法中调用 `stopScanning()` 后,会话被停止 - 重新扫描时,会话可能没有正确重启 - 缺少会话状态的验证和错误处理 ### 2. **时序问题** - 延迟时间过短(0.1秒),可能导致会话重启失败 - 没有等待会话完全停止就开始重启 - 缺少会话状态的检查机制 ### 3. **错误处理缺失** - 没有检查会话是否真的在运行 - 缺少会话启动失败的重试机制 - 没有提供详细的调试信息 ## 🛠️ 修复方案 ### 1. **优化会话重启逻辑** #### **改进 `restartScanning()` 方法** ```swift func restartScanning() { logInfo("🔄 重新开始扫描", className: "ScannerViewModel") // 确保在主线程执行UI相关操作 DispatchQueue.main.async { [weak self] in guard let self = self else { return } // 先停止当前会话 if self.captureSession?.isRunning == true { logInfo("🔄 停止当前运行的扫描会话", className: "ScannerViewModel") self.captureSession?.stopRunning() } // 重置检测状态 self.detectedCodes = [] // 延迟后重新启动会话(增加延迟时间) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { guard let self = self else { return } logInfo("🔄 准备重新启动扫描会话", className: "ScannerViewModel") // 在后台线程启动会话 DispatchQueue.global(qos: .userInitiated).async { self.captureSession?.startRunning() // 检查会话状态 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { if self.captureSession?.isRunning == true { logInfo("✅ 扫描会话已成功重新启动", className: "ScannerViewModel") } else { logWarning("⚠️ 扫描会话启动失败,尝试重新启动", className: "ScannerViewModel") // 如果启动失败,再次尝试 DispatchQueue.global(qos: .userInitiated).async { self.captureSession?.startRunning() DispatchQueue.main.async { if self.captureSession?.isRunning == true { logInfo("✅ 扫描会话第二次尝试启动成功", className: "ScannerViewModel") } else { logError("❌ 扫描会话启动失败", className: "ScannerViewModel") } } } } } } } } } ``` ### 2. **增强会话状态管理** #### **添加会话状态检查方法** ```swift func isSessionRunning() -> Bool { return captureSession?.isRunning == true } func checkSessionStatus() { let isRunning = captureSession?.isRunning == true logInfo("📊 扫描会话状态检查: \(isRunning ? "运行中" : "已停止")", className: "ScannerViewModel") if !isRunning { logWarning("⚠️ 扫描会话未运行,尝试重新启动", className: "ScannerViewModel") startScanning() } } ``` #### **改进 `startScanning()` 方法** ```swift func startScanning() { logInfo("🔄 开始扫描", className: "ScannerViewModel") // 检查会话是否已经在运行 if captureSession?.isRunning == true { logInfo("ℹ️ 扫描会话已经在运行", className: "ScannerViewModel") return } DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } self.captureSession?.startRunning() // 检查启动状态 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { if self.captureSession?.isRunning == true { logInfo("✅ 扫描会话启动成功", className: "ScannerViewModel") } else { logWarning("⚠️ 扫描会话启动失败", className: "ScannerViewModel") } } } } ``` #### **改进 `stopScanning()` 方法** ```swift func stopScanning() { logInfo("🔄 停止扫描", className: "ScannerViewModel") // 检查会话是否在运行 if captureSession?.isRunning == true { DispatchQueue.global(qos: .userInitiated).async { [weak self] in self?.captureSession?.stopRunning() DispatchQueue.main.async { logInfo("✅ 扫描会话已停止", className: "ScannerViewModel") } } } else { logInfo("ℹ️ 扫描会话已经停止", className: "ScannerViewModel") } } ``` ### 3. **增强重新扫描流程** #### **改进 `resetToScanning()` 方法** ```swift private func resetToScanning() { logInfo("🔄 ScannerView 开始重置到扫描状态", className: "ScannerView") // 重置UI状态 showPreviewPause = false // 重置扫描状态并重新开始 scannerViewModel.resetDetection() scannerViewModel.restartScanning() // 延迟检查会话状态 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { logInfo("🔍 检查扫描会话状态", className: "ScannerView") self.scannerViewModel.checkSessionStatus() } logInfo("✅ ScannerView 已重置到扫描状态", className: "ScannerView") } ``` ### 4. **添加调试功能** #### **调试按钮** 在 DEBUG 模式下添加会话状态检查按钮: ```swift // 调试按钮:检查会话状态 #if DEBUG Button(action: { logInfo("🔍 调试:检查扫描会话状态", className: "CodePositionOverlay") // 这里可以添加会话状态检查逻辑 }) { Image(systemName: "info.circle") .font(.system(size: 16, weight: .medium)) .foregroundColor(.yellow) .padding(8) .background(Color.black.opacity(0.6)) .clipShape(Circle()) } .padding(.trailing, 10) .padding(.top, 25) #endif ``` ## 📱 修复后的功能特性 ### 1. **会话状态管理** - ✅ 正确的会话启动/停止逻辑 - ✅ 会话状态检查和验证 - ✅ 自动重试机制 ### 2. **时序优化** - ✅ 增加延迟时间(0.5秒) - ✅ 等待会话完全停止后再重启 - ✅ 分阶段的状态检查 ### 3. **错误处理** - ✅ 详细的日志记录 - ✅ 会话状态验证 - ✅ 失败重试机制 ### 4. **调试支持** - ✅ 会话状态检查方法 - ✅ 调试按钮(DEBUG 模式) - ✅ 详细的操作日志 ## 🧪 测试方法 ### 1. **基本重新扫描测试** 1. 扫描包含多个二维码的图片 2. 等待预览暂停状态 3. 点击重新扫描按钮 4. 验证是否返回扫描状态 5. 检查控制台日志输出 ### 2. **扫描恢复测试** 1. 重新扫描后,移动设备对准二维码 2. 验证是否能重新检测到二维码 3. 检查扫描会话是否正常运行 ### 3. **会话状态测试** 1. 使用调试按钮检查会话状态 2. 验证会话状态检查逻辑 3. 测试自动重试机制 ### 4. **边界情况测试** 1. 快速连续点击重新扫描按钮 2. 在不同设备方向上测试 3. 在不同屏幕尺寸下测试 ## 🔧 技术实现细节 ### 1. **线程管理** - 主线程:UI 状态更新和日志记录 - 后台线程:会话启动/停止操作 - 适当的延迟确保操作顺序 ### 2. **状态同步** - 使用 `@Published` 属性同步状态 - 通过回调函数传递状态变化 - 确保 UI 和业务逻辑的一致性 ### 3. **错误恢复** - 会话启动失败时自动重试 - 状态检查失败时自动修复 - 提供详细的错误信息 ### 4. **性能优化** - 使用适当的 QoS 级别 - 避免不必要的会话操作 - 优化延迟时间设置 ## 📋 修复检查清单 - ✅ 优化会话重启逻辑 - ✅ 增加延迟时间(0.5秒) - ✅ 添加会话状态检查 - ✅ 实现自动重试机制 - ✅ 改进错误处理 - ✅ 增强日志记录 - ✅ 添加调试功能 - ✅ 确保代码编译通过 ## 🎯 预期效果 修复后,用户应该能够: 1. **正常重新扫描**:点击重新扫描按钮后能正确返回扫描状态 2. **持续扫描功能**:重新扫描后能继续检测二维码 3. **稳定运行**:扫描会话能正确启动和运行 4. **错误恢复**:即使出现问题也能自动恢复 ## 🚀 部署说明 1. **编译验证**:确保项目能够正常编译 2. **功能测试**:测试重新扫描功能是否正常 3. **扫描测试**:验证重新扫描后是否能继续检测 4. **性能测试**:确保修复不会影响应用性能 通过这些修复,重新扫描后无法扫描的问题应该得到根本解决,用户体验将显著提升。