57 lines
1.9 KiB
Swift
57 lines
1.9 KiB
Swift
import AVFoundation
|
|
|
|
/// 扫码采集会话的配置与运行接口,便于独立验证生命周期顺序。
|
|
protocol QRCodeCaptureSession: AnyObject {
|
|
/// 当前是否正在采集。
|
|
var isRunning: Bool { get }
|
|
/// 开始批量配置。
|
|
func beginConfiguration()
|
|
/// 提交批量配置。
|
|
func commitConfiguration()
|
|
/// 启动采集。
|
|
func startRunning()
|
|
/// 停止采集。
|
|
func stopRunning()
|
|
}
|
|
|
|
extension AVCaptureSession: QRCodeCaptureSession {}
|
|
|
|
/// 在同一串行队列中配置和启停相机,避免配置提交与启动交叉执行。
|
|
final class QRCodeCaptureSessionController {
|
|
private let session: QRCodeCaptureSession
|
|
private let queue: DispatchQueue
|
|
private var isConfigured = false
|
|
|
|
/// 创建会话生命周期控制器;队列必须为串行队列。
|
|
init(session: QRCodeCaptureSession,
|
|
queue: DispatchQueue = DispatchQueue(label: "com.zhifly.suixinkan.qr-capture")) {
|
|
self.session = session
|
|
self.queue = queue
|
|
}
|
|
|
|
/// 在配置事务内添加输入输出,提交完成后在主线程通知结果。
|
|
func configure(_ configuration: @escaping () -> Bool, completion: @escaping (Bool) -> Void) {
|
|
queue.async { [self] in
|
|
if !isConfigured {
|
|
session.beginConfiguration()
|
|
isConfigured = configuration()
|
|
session.commitConfiguration()
|
|
}
|
|
let succeeded = isConfigured
|
|
DispatchQueue.main.async { completion(succeeded) }
|
|
}
|
|
}
|
|
|
|
/// 按提交顺序更新运行状态,运行状态的读取也限定在会话队列内。
|
|
func setRunning(_ shouldRun: Bool) {
|
|
queue.async { [self] in
|
|
if shouldRun {
|
|
guard isConfigured, !session.isRunning else { return }
|
|
session.startRunning()
|
|
} else if session.isRunning {
|
|
session.stopRunning()
|
|
}
|
|
}
|
|
}
|
|
}
|