当nsviewcontroller在swift下从故事板实例化时,似乎在某个地方有一个引用循环。
多次调用以下代码将实例化并设置新的视图控制器,但旧的视图控制器永远不会解除锁定。在代码中,containerViewController
是应包含单个nsviewcontroller的nsviewcontroller,containerView
是containerViewController
中的子视图,identifier
是要实例化的情节提要标识符。
// Remove any sub viewcontrollers and their views
for viewController in containerViewController.childViewControllers as [NSViewController] {
viewController.view.removeFromSuperview()
viewController.removeFromParentViewController()
}
// Create and set up the new view controller and view.
let viewController = storyboard!.instantiateControllerWithIdentifier(identifier) as NSViewController
let view = viewController.view
view.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(viewController.view)
containerViewController.addChildViewController(viewController)
containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|", options: nil, metrics: nil, views: ["view": view]))
containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: nil, metrics: nil, views: ["view": view]))
(示例项目不再可用)
我用了一个苹果TSI,他们同意这是一个bug,我已经提交了,但我希望有人已经提出了这一点,现在视为nsviewcontrollers和故事板是事实上的OSX。你是如何解决这个问题的?或者它不会影响到其他人,我做错了什么?
预边界编辑:每个视图控制器必须能够从代码链接到任何其他视图控制器,因为目的地是动态确定的。这似乎可以作为一种选择来消除隔阂。
错误已修复
从Xcode6.3开始,这不再是一个bug。
最佳答案
另一个答案。
似乎只有故事板上定义的段可以执行视图控制器释放。
所以,这里有一个非常难看,但工作的解决方案。
class DismissSegue: NSStoryboardSegue {
var nextViewControllerIdentifier:String?
override func perform() {
let src = self.sourceController as NSViewController
let windowController = src.view.window!.windowController() as TopLevelWindowController
src.view.removeFromSuperview()
src.removeFromParentViewController()
if let identifier = nextViewControllerIdentifier {
windowController.setNewViewController(identifier)
}
}
}
class TopLevelWindowController: NSWindowController {
var containerView: NSView!
var containerViewController: ContainerViewController! {
didSet {
setNewViewController("FirstView")
}
}
func setNewViewController(identifier: String) {
// Create and set up the new view controller and view.
let viewController = storyboard!.instantiateControllerWithIdentifier(identifier) as NSViewController
let view = viewController.view
view.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(viewController.view)
containerViewController.addChildViewController(viewController)
containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|", options: nil, metrics: nil, views: ["view": view]))
containerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: nil, metrics: nil, views: ["view": view]))
}
}
class ContainerViewController: NSViewController {
@IBOutlet var containerView: NSView!
override func viewDidAppear() {
super.viewDidAppear()
if let window = view.window {
if let topLevelWindowController = window.windowController() as? TopLevelWindowController {
topLevelWindowController.containerView = containerView
topLevelWindowController.containerViewController = self
}
}
}
}
class FirstViewController: NSViewController {
required init?(coder: NSCoder) {
super.init(coder: coder)
let pointerAddress = NSString(format: "%p", unsafeBitCast(self, Int.self))
NSLog("First VC init at \(pointerAddress)")
}
deinit {
let pointerAddress = NSString(format: "%p", unsafeBitCast(self, Int.self))
NSLog("First VC de-init at \(pointerAddress)")
}
override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) {
if let segue = segue as? DismissSegue {
segue.nextViewControllerIdentifier = "SecondView"
}
}
}
class SecondViewController: NSViewController {
required init?(coder: NSCoder) {
super.init(coder: coder)
let pointerAddress = NSString(format: "%p", unsafeBitCast(self, Int.self))
NSLog("Second VC init at \(pointerAddress)")
}
deinit {
let pointerAddress = NSString(format: "%p", unsafeBitCast(self, Int.self))
NSLog("Second VC de-init at \(pointerAddress)")
}
override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) {
if let segue = segue as? DismissSegue {
segue.nextViewControllerIdentifier = "FirstView"
}
}
}
修改故事板的步骤:
断开按钮的连接。
使用normal
@IBAction
创建“虚拟”视图控制器场景。将自定义段从按钮连接到“虚拟”。
如图所示配置这些segue。
如果这个解决方案不符合您的要求,请告诉我。
关于macos - NSViewController引用周期与 Storyboard,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26836515/