如何让iOS NFC交互函数同步执行?无需usleep等待结果
解决iOS NFC ISO15693命令同步执行问题
你的核心问题是sendI2CCommand依赖异步的NFC请求,但当前实现无法等待异步回调完成就返回结果,用usleep是不可靠的临时方案,信号量崩溃则是因为线程死锁——NFC回调默认在主线程执行,若你在主线程调用semaphore.wait(),主线程会被阻塞,回调永远无法触发signal(),导致死锁。
以下是两种可靠的解决方案:
方案一:修复信号量实现(兼容iOS 14及以下)
确保信号量的等待操作在后台线程执行,同时所有分支都必须调用signal(),避免永久阻塞。修改后的代码如下:
public static func sendI2CCommand(tag: NFCISO15693Tag, command: UInt8) -> String { var res = "" let semaphore = DispatchSemaphore(value: 0) tag.sendRequest(requestFlags: 0x12, commandCode: 0xD4, data: Data([0x04, 0x02, 0x00, command])) { result in switch result { case .success: semaphore.signal() case .failure: tag.sendRequest(requestFlags: 0x12, commandCode: 0xD5, data: Data([0x04, 0x02, 0x00])) { secondResult in switch secondResult { case .success: semaphore.signal() case .failure: tag.sendRequest(requestFlags: 0x12, commandCode: 0xD2, data: Data([0x04, 0x00, 0x06])) { thirdResult in switch thirdResult { case .success((let responseFlag, let response2)): var foo = response2 foo.insert(responseFlag.rawValue, at: 0) let responseHex = foo.hexadecimalCompressed.substring(with: 2..<4) res = responseHex semaphore.signal() case .failure, default: semaphore.signal() } } default: semaphore.signal() } } default: semaphore.signal() } } // 在后台线程等待,避免主线程死锁 DispatchQueue.global().sync { semaphore.wait() } return res }
方案二:使用Async/Await(iOS 15+,推荐)
通过withCheckedThrowingContinuation将异步的sendRequest包装为Async函数,彻底消除回调嵌套和线程死锁问题,代码更易维护。
1. 封装NFC请求为Async方法
extension NFCISO15693Tag { func sendRequestAsync(requestFlags: UInt8, commandCode: UInt8, data: Data) async throws -> (NFCISO15693ResponseFlag, Data) { return try await withCheckedThrowingContinuation { continuation in self.sendRequest(requestFlags: requestFlags, commandCode: commandCode, data: data) { result in switch result { case .success(let response): continuation.resume(returning: response) case .failure(let error): continuation.resume(throwing: error) } } } } }
2. 修改sendI2CCommand为Async函数
public static func sendI2CCommand(tag: NFCISO15693Tag, command: UInt8) async -> String { var res = "" do { // 执行第一条命令 try await tag.sendRequestAsync(requestFlags: 0x12, commandCode: 0xD4, data: Data([0x04, 0x02, 0x00, command])) } catch { do { // 第一条失败,执行第二条 try await tag.sendRequestAsync(requestFlags: 0x12, commandCode: 0xD5, data: Data([0x04, 0x02, 0x00])) } catch { do { // 第二条失败,执行第三条并处理结果 let (responseFlag, response2) = try await tag.sendRequestAsync(requestFlags: 0x12, commandCode: 0xD2, data: Data([0x04, 0x00, 0x06])) var foo = response2 foo.insert(responseFlag.rawValue, at: 0) let responseHex = foo.hexadecimalCompressed.substring(with: 2..<4) res = responseHex } catch { // 处理所有错误,返回空字符串或自定义错误标记 res = "" } } } return res }
3. 调用方式
用Task启动异步任务,自动按顺序执行命令:
Task { guard let tag = self.tag else { return } let fw_id = await NFCUtils.sendI2CCommand(tag: tag, command: NFCConstants.CONFIG_FW_ID) print("Read FirmwareID \(fw_id)") let sw_id = await NFCUtils.sendI2CCommand(tag: tag, command: NFCConstants.CONFIG_SW_ID) print("Read SotfwareID \(sw_id)") let ex_id = await NFCUtils.sendI2CCommand(tag: tag, command: NFCConstants.CONFIG_EX_ID) print("Read ExternalID \(ex_id)") }
内容的提问来源于stack exchange,提问作者tiamat
相关产品推荐
相关产品推荐

