SwiftUI中如何解析BLE通知并通过回调执行CoreData存储操作?
SwiftUI中BLE无响应请求的通知回调处理方案
需求:实现BLE交互,手机发送.withoutResponse类型请求,设备通过BLE通知回复,仅在收到设备正常响应后执行CoreData存储操作。
核心思路
利用Swift的异步等待机制(CheckedContinuation),将BLE的回调式通知转换为异步函数,让saveDevice等待设备响应确认后再执行存储操作;同时维护一个请求映射表,确保每个设备的请求能匹配到对应的响应回调。
代码修改步骤
1. 在BLE管理类中添加请求回调映射表
用于暂存等待响应的请求回调,避免多个设备请求混淆:
// 存储等待响应的回调,key为「设备UUID+请求方法」的组合字符串 private var pendingRequests: [String: CheckedContinuation<Bool, Error>] = [:]
2. 修改saveDevice为异步函数
用withCheckedThrowingContinuation挂起函数,等待设备响应:
func saveDevice(identifier: UUID, name: String, type: Int) async throws { let requestData = Request.deviceSave(name: name, type: type) writeToIdentifier(identifier: identifier, data: requestData) // 生成唯一请求键,区分不同设备的不同请求(1是DEVICE SAVE对应的method值) let requestKey = "\(identifier.uuidString)-1" // 挂起函数,等待响应回调 try await withCheckedThrowingContinuation { continuation in pendingRequests[requestKey] = continuation } // 只有收到成功响应后,才执行CoreData存储 CoreDataModel.shared.saveDevice(uuid: identifier, name: name, type: Int16(type)) }
3. 修改parseResponse触发回调
收到设备通知后,匹配对应的请求并处理结果:
func parseResponse(data: Data, identifier: UUID) { let method: UInt8 = data.first! let requestKey = "\(identifier.uuidString)-\(method)" // 取出对应的回调,若不存在则直接返回 guard let continuation = pendingRequests.removeValue(forKey: requestKey) else { return } switch method { case 1: print("Method: DEVICE SAVE") let isSuccess = data[5] == 1 print("Is configured: \(isSuccess)") if isSuccess { // 响应成功,恢复函数执行 continuation.resume(returning: true) } else { // 响应失败,抛出错误 continuation.resume(throwing: NSError(domain: "BLEError", code: -1, userInfo: [NSLocalizedDescriptionKey: "设备保存失败"])) } default: // 处理未知请求类型 continuation.resume(throwing: NSError(domain: "BLEError", code: -2, userInfo: [NSLocalizedDescriptionKey: "未知请求方法"])) } }
4. 处理设备断开等异常情况
在设备断开时清理pending请求,避免函数永久挂起:
func peripheral(_ peripheral: CBPeripheral, didDisconnectPeripheral error: Error?) { let deviceUUID = peripheral.identifier.uuidString // 移除该设备的所有等待请求 pendingRequests.keys.forEach { key in if key.starts(with: deviceUUID) { if let continuation = pendingRequests.removeValue(forKey: key) { let disconnectError = error ?? NSError(domain: "BLEError", code: -3, userInfo: [NSLocalizedDescriptionKey: "设备断开连接"]) continuation.resume(throwing: disconnectError) } } } }
5. SwiftUI视图中调用异步函数
用Task包裹异步调用,处理成功/失败场景:
Button("保存设备") { Task { do { try await bleManager.saveDevice(identifier: targetDeviceUUID, name: "我的设备", type: 1) print("设备已成功保存至CoreData") // 可添加UI提示,比如弹出Toast } catch { print("保存失败:\(error.localizedDescription)") // 显示错误提示 } } }
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

