首页 > 解决方案 > NSNotification 观察者不会被删除,除非它被触发一次

问题描述

总之

如果用户在 VC1 上拍摄带有叠加层的照片,则会触发通知。当我展示 VC2 时,相应的观察者会被我的方法删除。

如果用户没有在 VC1 上拍照,则不会触发通知观察者。相同的移除方法称为 VC2,但观察者保持活动状态并导致 VC2 照片捕获时出现不良行为。

完整解释

我有一个注册表单,用户可以在其中拍摄一张可选的脸部照片。我正在使用一个简单的UIImagePickerController并呈现“护照”样式的叠加层。

if sourceType == .camera {
    imagePickerController.cameraDevice = .front
    let overlay = PassportOverlayView(frame: imagePickerController.view.frame)
    imagePickerController.cameraOverlayView = overlay
}

覆盖层覆盖了“重新拍摄”和“选择”按钮,UIImagePickerController因此我观察以下内容NSNotifications以在拍摄照片时移除覆盖层,并在用户希望重新拍摄照片时根据需要重新添加。

NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object:nil, queue:nil, using: { note in
    self.imagePickerController.cameraOverlayView = nil
})
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidRejectItem"), object:nil, queue:nil, using: { note in
    self.imagePickerController.cameraOverlayView = PassportOverlayView(frame: self.imagePickerController.view.frame)
})

一切都按预期工作。我在下一个UIViewController推送到堆栈之前删除了通知。

func removeObservers(){
    print("remove Observers")
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidRejectItem"), object: nil)
}

如果用户拍摄了一张照片并因此调用了观察者在下一张上添加了一张照片UIViewController,这不需要叠加,则可以正常工作。

但是,如果用户没有在第一张照片上拍照UIViewController[这对于我的应用程序来说非常好],他们会在第二张照片上遇到问题UIViewController

在这两个场景中,该removeObservers()函数都被调用。“remove Observers”在这两种情况下都会打印到控制台。然而,当用户试图从一秒钟内拍照时,UIViewController应用程序崩溃Unexpectedly found nil while implicitly unwrapping an Optional value并指向通知self.imagePickerController.cameraOverlayView = nil行。_UIImagePickerControllerUserDidCaptureItem

我理解错误,它试图删除一个cameraOverlayView不存在的。我无法理解的是为什么当我相信它已经被移除时观察者仍然在那里。如果用户使用 拍摄第一张照片cameraOverlayView并触发_UIImagePickerControllerUserDidCaptureItem通知,则没有问题。观察者被删除,随后UIImagePickerControllers没有同样的问题。

任何帮助将不胜感激。

标签: swiftuiimagepickercontrollernsnotifications

解决方案


我想我知道你的问题是什么。保留周期导致观察者无法成功删除。之所以有保留周期,是因为您在设置通知的闭包中使用了对 self 的强引用。以下是您修复它的方法:

NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object:nil, queue:nil, using: { [unowned self] note in
    self.imagePickerController.cameraOverlayView = nil
})
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidRejectItem"), object:nil, queue:nil, using: { [unowned self] note in
    self.imagePickerController.cameraOverlayView = PassportOverlayView(frame: self.imagePickerController.view.frame)
})

同样,您不必担心删除观察者,因此请尝试在没有 removeObserver 的情况下运行您的代码,它应该可以工作。

希望这可以帮助。


推荐阅读