Swift MacOX - Popover segue 创建多个视图控制器实例而不在它们被关闭时销毁它们
Swift MacOX - Popover segue creates multiple view controller instances without destroying them when they are dismissed
我正在像这样在情节提要中创建弹出式样式的视图控制器
然后我点击按钮,视图控制器显示,当我点击外面的任何地方时,视图控制器是 "dismissed"。
然而,当我再次单击该按钮时,视图控制器的一个新实例启动,而前一个实例仍然是 运行。我试过 deinit
但是当视图控制器是 "dismissed".
时它没有被调用
如何在点击外部时销毁视图控制器实例,或者 "show" 已经创建的实例?
我在视图控制器中的代码:
class FileTransViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(updateProgress), userInfo: nil, repeats: true)
//print(123)
print("\(self)")
}
deinit {
print("destroyed")
if let timer = timer {
timer.invalidate()
}
}
@objc func updateProgress() {
print("updating progress")
}
}
问题与弹出窗口无关。你正在泄漏,因为你保留了计时器,而计时器保留了你——一个经典的保留循环。
要打破循环,您必须使计时器无效。您不能在 deinit
中执行此操作,因为根据定义,只有在您打破循环之后才能调用它。 NSPopover.willCloseNotification
可能是个好机会。
正如@matt 所说,您的保留周期有问题。您可以使用 Timer
和块来避免它,您可以在块中为 self
声明 weak
引用
timer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { [weak self] timer in
guard let self = self else {
timer.invalidate()
return
}
print("updating progress")
}
在这种情况下你也不需要 deinit
因为你在 guard
的 else
块中使计时器无效而且你也不需要变量 timer
如果你不想在其他地方手动使计时器无效,你可以只写 Timer
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(...) { ... }
}
我正在像这样在情节提要中创建弹出式样式的视图控制器
然后我点击按钮,视图控制器显示,当我点击外面的任何地方时,视图控制器是 "dismissed"。
然而,当我再次单击该按钮时,视图控制器的一个新实例启动,而前一个实例仍然是 运行。我试过 deinit
但是当视图控制器是 "dismissed".
如何在点击外部时销毁视图控制器实例,或者 "show" 已经创建的实例?
我在视图控制器中的代码:
class FileTransViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(updateProgress), userInfo: nil, repeats: true)
//print(123)
print("\(self)")
}
deinit {
print("destroyed")
if let timer = timer {
timer.invalidate()
}
}
@objc func updateProgress() {
print("updating progress")
}
}
问题与弹出窗口无关。你正在泄漏,因为你保留了计时器,而计时器保留了你——一个经典的保留循环。
要打破循环,您必须使计时器无效。您不能在 deinit
中执行此操作,因为根据定义,只有在您打破循环之后才能调用它。 NSPopover.willCloseNotification
可能是个好机会。
正如@matt 所说,您的保留周期有问题。您可以使用 Timer
和块来避免它,您可以在块中为 self
weak
引用
timer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { [weak self] timer in
guard let self = self else {
timer.invalidate()
return
}
print("updating progress")
}
在这种情况下你也不需要 deinit
因为你在 guard
的 else
块中使计时器无效而且你也不需要变量 timer
如果你不想在其他地方手动使计时器无效,你可以只写 Timer
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(...) { ... }
}