Swift 5使用通知传值:扫码后ViewController未触发通知回调问题
代码问题定位
- 通知名称不匹配:发送通知用的名称是
Notification.Name("scannedInfo"),监听用的是Notification.Name("ScanInfo"),名称不一致直接导致无法触发监听方法 - 观察者注册时机完全错误:你在扫描完成后已经先发送了通知,又在dismiss的完成回调里新创建了一个ViewController1实例才去注册观察者,首先新创建的实例不是你之前发起跳转的原VC1实例,其次通知是即时发送的,注册前发送的通知不会被后续注册的观察者收到
- 非全屏modal和这个问题没有关联,你现在的问题是逻辑错误,和弹出样式无关
修复方案
方案1:使用闭包回调(更推荐,逻辑更清晰,无通知全局污染)
- 首先在
scanBarcode视图控制器中定义回调闭包:
class scanBarcode: UIViewController { // 定义扫描完成回调,参数为你要传回的条码值和value2 var scanCompletion: ((_ barcode: String, _ value2: String) -> Void)? // 扫描完成的处理方法修改为: func processScan() { print("Process Scanned") let barcode = "123" // 替换为实际扫描得到的条码值 let value2 = "Yes" // 先触发回调传值,再dismiss scanCompletion?(barcode, value2) dismiss(animated: true) } }
- 弹出扫描页的时候绑定回调:
let scannerView = scanBarcode() // 绑定回调,直接拿到返回值 scannerView.scanCompletion = { [weak self] barcode, value2 in guard let self = self else { return } self.barcode = barcode self.value2 = value2 print(barcode) print(value2) // 拿到值后可以直接执行刷新UI等后续操作 } let navigationController = UINavigationController(rootViewController: scannerView) navigationController.modalPresentationStyle = .formSheet self.present(navigationController, animated: true)
方案2:修正通知用法(如果一定要用通知的话)
- 统一通知名称,建议定义为全局常量避免拼写错误:
extension Notification.Name { static let scannedBarcodeInfo = Notification.Name("scannedBarcodeInfo") }
- ViewController1需要在弹出扫描页之前就注册观察者,比如在viewDidLoad里注册:
class ViewController1: UIViewController { var barcode: String? var value2: String? override func viewDidLoad() { super.viewDidLoad() // 页面加载完成就注册观察者 NotificationCenter.default.addObserver(self, selector: #selector(scanInfo(notification:)), name: .scannedBarcodeInfo, object: nil) } @objc func scanInfo(notification: Notification) { print("ScanInfo") barcode = notification.userInfo?["barcodeValue"] as? String value2 = notification.userInfo?["value2"] as? String print(barcode ?? "空值") print(value2 ?? "空值") } // 页面销毁时移除观察者,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } }
- 扫描完成的方法修改为:
func processScan() { print("Process Scanned") NotificationCenter.default.post(name: .scannedBarcodeInfo, object: nil, userInfo:["barcodeValue": "123","value2": "Yes"]) dismiss(animated: true) }
直接删除原代码中dismiss completion里创建ViewController1调用observeScanned的错误逻辑即可。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

