NSNotification观察者除非被触发一次,否则不会被删除

问题描述 投票:1回答:2

摘要

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

[如果用户未在VC1上拍照,则不会触发通知查看器。提出了与VC2相同的删除方法,但观察者保持活动状态,并且会因VC2照片捕获而导致不良行为。

完整说明

我有一个注册表,用户可以在其中注册自己的面部照片。我正在使用简单的UIImagePickerController,并呈现“护照”样式的覆盖物。

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

叠加层覆盖了UIImagePickerController的'retake'和'choose'按钮,因此我观察到以下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()功能。两次都将“删除观察者”打印到控制台。但是,当用户尝试从第二个UIViewController内拍摄照片时,该应用会因为Unexpectedly found nil while implicitly unwrapping an Optional value而崩溃,并将我指向self.imagePickerController.cameraOverlayView = nil通知的_UIImagePickerControllerUserDidCaptureItem行。

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

任何帮助将不胜感激。

swift uiimagepickercontroller nsnotifications
2个回答
0
投票

我想我知道你的问题是什么。保留周期导致无法成功删除观察者。之所以具有保留周期,是因为您在设置通知的闭包中使用了对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的情况下运行代码,它应该可以工作。

希望这会有所帮助。


0
投票

收到Reddit帖子的回复后,我已经解决了我的问题。

添加我的observers时,我应该已经明确了,并将self设置为对象,而不是nil。当我第一次编写代码时,我认为nil不会成为问题,因为我自己会删除observers

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

上面的代码现在可以按预期工作。

将对象设置为自身时,ARC会处理observer,并会自动将其删除。

我最初的问题是,为什么observer除非被使用过,否则为什么不被删除,我只能怀疑observer一直在等待直到它被首次调用,并为object分配了一些东西。 C0]。

不管后台发生了什么,在声明观察者时我都会更加小心和明确。

© www.soinside.com 2019 - 2024. All rights reserved.