Swift 除非已触发一次,否则不会删除NSO通知

Swift 除非已触发一次,否则不会删除NSO通知,swift,uiimagepickercontroller,nsnotifications,Swift,Uiimagepickercontroller,Nsnotifications,总之 如果用户在VC1上使用覆盖层拍摄照片,则会触发通知。通过我的方法,相应的观察者被移除为I present VC2 如果用户没有在VC1上拍照,则不会触发通知观察者。相同的移除方法称为VC2,但观察者保持活动状态,并通过VC2照片捕获导致不必要的行为 完整解释 我有一张登记表,用户可以在其中随意拍照。我正在使用一个简单的UIImagePickerController并呈现一个“passport”样式的覆盖 if sourceType == .camera { imagePickerC

总之

如果用户在VC1上使用覆盖层拍摄照片,则会触发通知。通过我的方法,相应的观察者被移除为I present VC2

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

完整解释

我有一张登记表,用户可以在其中随意拍照。我正在使用一个简单的
UIImagePickerController
并呈现一个“passport”样式的覆盖

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()
函数。在这两种情况下,“移除观察者”都会打印到控制台上。然而,当用户试图从第二个
UIViewController
内拍照时,应用程序崩溃,因为它
在隐式展开可选值时意外发现nil,并将我指向
\u UIImagePickerControllerUserDidCaptureItem
通知

我理解错误,它正在尝试删除不存在的
cameraOverlayView
。我不明白的是,为什么观察家还在那里,而我相信它已经被移除了。如果用户使用
cameraOverlayView
拍摄第一张照片并触发
\u UIImagePickerControllerUserDidCaptureItem
通知,则不存在问题。观察者将被删除,后续的
UIImagePickerController
不会出现同样的问题


非常感谢您的帮助。

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


希望这能有所帮助。

我认为您不必再担心删除观察者的问题(从iOS9开始)。因此,您尝试在不使用RemoveObservators函数的情况下运行代码,看看它是否有效。如果不起作用,请将您的Observator分配给一个变量,并使用该变量调用RemoveObservator:谢谢@rs7,我以前尝试过不使用RemoveObservators函数,看看iOS是否为我这么做,但没有乐趣。使用变量也不会改变任何事情。我仍然有一个奇怪的场景,即观察者只有在ViewController 1Thanks上使用后才会被删除,我将尝试按照您的建议添加
[无主自我]
。仍然无法理解为什么它会在使用时删除,但如果它不在我的原始代码中则删除。使用[unowned self]解决了您的问题吗?您的remove observer函数是从Denit调用的?我还没有尝试过。明天早上我要做的第一件事就是试试。我没有从Denit调用remove observer,它只是在一个按钮点击的动作中调用,该动作将下一个VC推到堆栈上。我不认为使用图像选择器控制器意味着没有保留周期??嗯,我自己也有点困惑。我不知道这是一个保留周期还是内存泄漏。在闭包中使用self意味着有一个指向UIImagePickerController的强引用。当您通过单击按钮离开UIImagePickerController时,由于该强引用,UIImagePickerController不会被解除分配。现在让人困惑的是为什么removeObserver不起作用。我真的很想知道[无主的自我]是否能解决你的问题。同时,我会继续挖掘。抱歉耽搁了```[无主的自我]并没有带来什么不同。内存图也没有显示任何泄漏或保留周期。