草庐IT

macos - 带有 Storyboard的 NSViewController 引用循环

coder 2023-09-13 原文

NSViewController,当在 Swift 下从 Storyboard实例化时,似乎在某处有一个引用循环。

多次调用下面的代码将实例化并设置一个新的 View Controller ,但旧的 View Controller 永远不会被释放。在代码中,containerViewController 是一个 NSViewController,它应该包含一个 NSViewController,containerViewcontainerViewController 中的 subview ,identifier 是要实例化的 Storyboard标识符。

// 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]))

(示例项目不再可用)

我使用了 Apple TSI,他们认为这是一个错误,我已将其提交,但我希望其他人会反对这个问题,因为现在看到 NSViewControllers 和 Storyboard现在是 OSX 上的事实。你是如何解决这个问题的?还是它不会影响其他任何人而我做错了什么?

赏金前编辑:每个 View Controller 必须能够从代码链接到任何其他 View Controller ,因为目标是动态确定的。这似乎可以删除 segues。

错误修复

从 Xcode 6.3 开始,这不再是错误。

最佳答案

另一个答案。

似乎只有定义在 Storyboard 上的 segues 才能执行 View Controller 释放。 因此,这是一个非常丑陋但可行的解决方法。

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"
        }
    }
}

修改 Storyboard 的过程:

  1. 断开 @IBAction 与按钮的连接。
  2. 使用普通 NSViewController 创建“DUMMY” View Controller 场景。
  3. 将自定义 segues 从按钮连接到“DUMMY”。
  4. 如图所示配置这些 segue。

如果此解决方案不能满足您的需求,请告诉我。

关于macos - 带有 Storyboard的 NSViewController 引用循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26836515/

有关macos - 带有 Storyboard的 NSViewController 引用循环的更多相关文章

  1. ruby - 树顶语法无限循环 - 2

    我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

  2. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  5. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  6. ruby - Ruby 中的闭包和 for 循环 - 2

    我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对

  7. Ruby:如何使用带有散列的 'send' 方法调用方法? - 2

    假设我有一个类A,里面有一些方法。假设stringmethodName是这些方法之一,我已经知道我想给它什么参数。它们在散列中{'param1'=>value1,'param2'=>value2}所以我有:params={'param1'=>value1,'param2'=>value2}a=A.new()a.send(methodName,value1,value2)#callmethodnamewithbothparams我希望能够通过传递我的哈希以某种方式调用该方法。这可能吗? 最佳答案 确保methodName是一个符号,而

  8. ruby-on-rails - 带有 Pry 的 Rails 控制台 - 2

    当我进入Rails控制台时,我已将pry设置为加载代替irb。我找不到该页面或不记得如何将其恢复为默认行为,因为它似乎干扰了我的Rubymine调试器。有什么建议吗? 最佳答案 我刚发现问题,pry-railsgem。忘记了它的目的是让“railsconsole”打开pry。 关于ruby-on-rails-带有Pry的Rails控制台,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/question

  9. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

  10. ruby - Chef LW 资源属性默认值如何引用另一个属性? - 2

    我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我

随机推荐