Swift:如何仅在蓝牙写入完成后调用Siri意图的completion闭包?
解决方案:等待蓝牙写入完成后调用Siri Intent的Completion Handler
完全可以,而且这是解决你当前问题的核心方法——Siri快捷指令的Intent处理流程会在调用completion后立即结束,所以必须等蓝牙写入操作通过代理回调确认完成后,再执行completion,才能保证蓝牙流程不被中断。
修改后的代码示例
// 保存Intent的completion闭包,用于异步回调时调用 private var intentCompletion: ((SwitchIntentResponse) -> Void)? private var writeCompleted = false // 添加超时定时器,避免无限等待 private var timeoutTimer: Timer? // 代理函数:蓝牙写入完成后的回调 func writeConfirmed() { writeCompleted = true // 写入完成,触发completion finishIntentWithSuccess() } func handle(intent: SwitchIntent, completion: @escaping (SwitchIntentResponse) -> Void) { // 重置状态,避免上一次Intent的残留影响 writeCompleted = false intentCompletion = completion // 设置代理 BTHandler.shared.responseDelegate = self // 启动超时定时器(比如10秒超时) timeoutTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { [weak self] _ in self?.finishIntentWithFailure(code: .failure, message: "蓝牙写入超时") } // 开始扫描蓝牙设备 BTHandler.shared.scan { [weak self] in guard let self = self else { return } BTHandler.shared.centralManager.stopScan() // 执行写入操作 BTHandler.shared.write(btdevice: BTHandler.shared.discoveredDevice, command: .write) } } // 封装成功完成Intent的逻辑 private func finishIntentWithSuccess() { timeoutTimer?.invalidate() intentCompletion?(SwitchIntentResponse(code: .success, userActivity: nil)) // 清理资源 intentCompletion = nil } // 封装失败完成Intent的逻辑 private func finishIntentWithFailure(code: SwitchIntentResponseCode, message: String?) { timeoutTimer?.invalidate() let response = SwitchIntentResponse(code: code, userActivity: nil) response.errorMessage = message intentCompletion?(response) // 清理资源 intentCompletion = nil }
关键修改说明
- 保存completion闭包:因为蓝牙写入是异步操作,需要在代理回调
writeConfirmed中调用completion,所以要把闭包临时保存为实例变量。 - 状态重置:每次处理Intent前重置
writeCompleted,避免上次操作的状态干扰当前流程。 - 超时处理:添加定时器防止蓝牙操作无响应导致Intent长时间挂起,提升用户体验。
- 资源清理:完成Intent后及时清理闭包和定时器,避免内存泄漏。
内容的提问来源于stack exchange,提问作者schindt
相关产品推荐
相关产品推荐

