SwiftUI中使用Core NFC遇代理回调异常问题求助
解决SwiftUI中NFCNDEFReaderSessionDelegate回调不触发的问题
看起来你遇到的核心问题有两个:代理对象生命周期过短,以及CoreNFC版本兼容的方法实现问题,下面一步步给你拆解解决:
问题根源分析
- 实例生命周期问题:你在
scan()方法里创建的Nfc是局部变量,方法执行完就被ARC回收了。当NFC会话试图触发回调时,代理对象已经不存在,系统自然找不到对应的实现方法,这就是你看到Delegate does not implement -readerSessionDidBecomeActive:错误的原因。 - CoreNFC版本差异:iOS 13之后,
didDetectNDEFs方法被弃用,官方推荐使用didDetect tags方法,但这个新方法需要手动完成标签连接、NDEF状态查询、消息读取的完整流程,不是简单打印就能工作的。
修改后的完整代码
1. 重构Nfc类(实现ObservableObject+完整NFC流程)
import CoreNFC import SwiftUI class Nfc: NSObject, NFCNDEFReaderSessionDelegate, ObservableObject { // 用@Published把扫描结果传递给ContentView @Published var scanResult: String = "n/a" func start() { // 先检查设备是否支持NFC读取 guard NFCNDEFReaderSession.readingAvailable else { scanResult = "当前设备不支持NFC读取" return } let session = NFCNDEFReaderSession(delegate: self, queue: nil, invalidateAfterFirstRead: true) session.begin() print("NFC扫描会话已启动") } // iOS 11-12兼容方法(iOS13+已弃用) func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { processReceivedMessages(messages) session.invalidate() } // iOS13+必须实现的新方法:处理标签检测 func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) { guard let tag = tags.first else { session.invalidate(errorMessage: "未检测到NFC标签") return } // 连接到标签 session.connect(to: tag) { error in if let error = error { session.invalidate(errorMessage: "连接标签失败:\(error.localizedDescription)") return } // 查询标签的NDEF支持状态 tag.queryNDEFStatus { status, _, error in if let error = error { session.invalidate(errorMessage: "查询NDEF状态失败:\(error.localizedDescription)") return } switch status { case .notSupported: session.invalidate(errorMessage: "该标签不支持NDEF格式") case .readOnly, .readWrite: // 读取标签中的NDEF消息 tag.readNDEF { message, error in if let error = error { session.invalidate(errorMessage: "读取NDEF消息失败:\(error.localizedDescription)") return } if let message = message { self.processReceivedMessages([message]) } else { self.scanResult = "标签中无NDEF消息" } session.invalidate() } @unknown default: session.invalidate(errorMessage: "未知的NDEF状态") } } } } func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) { print("NFC会话已激活") } func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { if let readerError = error as? NFCReaderError { // 排除用户主动取消的情况 if readerError.code != .readerSessionInvalidationErrorUserCanceled { scanResult = "扫描错误:\(readerError.localizedDescription)" } } else { scanResult = "意外错误:\(error.localizedDescription)" } print("NFC会话已终止:\(error.localizedDescription)") } // 统一处理读取到的NDEF消息 private func processReceivedMessages(_ messages: [NFCNDEFMessage]) { let content = messages.flatMap { $0.records } .compactMap { String(data: $0.payload, encoding: .utf8) } .joined(separator: "\n") scanResult = content.isEmpty ? "未读取到有效内容" : content } }
2. 修改ContentView(持有Nfc实例)
struct ContentView: View { // 用@StateObject让Nfc实例在View生命周期内保持存活 @StateObject private var nfc = Nfc() var body: some View { VStack(spacing: 20) { Text(nfc.scanResult) .padding() .multilineTextAlignment(.center) Button(action: { nfc.start() }) { Text("扫描NFC标签") .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } // 当设备不支持NFC时禁用按钮 .disabled(!NFCNDEFReaderSession.readingAvailable) } .padding() } }
额外配置提醒
- 在
Info.plist中添加NFC权限描述:<key>NFCReaderUsageDescription</key> <string>需要使用NFC读取标签内容</string> - 必须使用真机测试,iOS模拟器不支持NFC功能。
- 确保测试设备是iPhone 7及以上(支持NFC读取),且已开启系统NFC功能。
内容的提问来源于stack exchange,提问作者CL So
相关产品推荐
相关产品推荐

