在 NSWindow 中呈现不同 NSViewController 的正确方法

Posted

技术标签:

【中文标题】在 NSWindow 中呈现不同 NSViewController 的正确方法【英文标题】:Correct method to present a different NSViewController in NSWindow 【发布时间】:2015-03-21 03:43:35 【问题描述】:

我正在开发一个应用程序,它是单个 NSWindow,单击窗口内的按钮将显示 NSViewController,并且该控制器中存在一个按钮,将显示不同的 NSViewController。我知道如何换出窗口中的视图,但我在尝试使用多个视图控制器时遇到了问题。我已经解决了这个问题,但我认为我没有以适当的方式完成此行为。

我原来在AppDelegate中定义了一个方法:

- (void)displayViewcontroller:(NSViewController *)viewController 
    BOOL ended = [self.window makeFirstResponder:self.window];
    if (!ended) 
        NSBeep();
        return;
    
    [self.box setContentView:viewController.view];

我为 AppDelegate 的 NSButton 设置了一个目标/操作,在这里我调用该方法来显示一个新的视图控制器:

- (IBAction)didTapContinue:(NSButton *)sender 
    NewViewController *newVC = [[NewViewController alloc] init];
    [self displayViewcontroller:newVC];

这确实有效 - 它呈现了新视图控制器的视图。但是,如果我随后单击该视图中具有位于其视图控制器类中的目标/操作设置的任何按钮,应用程序会立即崩溃。

要解决此问题,我必须将didTapContinue: 更改为以下内容:

- (IBAction)didTapContinue:(NSButton *)sender 
    NewViewController *newVC = [[NewViewController alloc] init];
    [self.viewControllers addObject:newVC];
    [self displayViewcontroller:[self.viewControllers lastObject]];

首先,您能解释一下为什么这样可以解决问题吗?似乎与控制器在内存中“保持”的方式有关,但我并不肯定。

我的问题是,如何设置它以便可以从任何视图控制器中换出视图?我正计划获取对 AppDelegate 的引用并使用我刚刚在该类中实例化的新控制器调用displayViewcontroller:,但这会导致崩溃。我需要先将它存储在数组中,然后将该引用发送到方法中。这是一种有效的方法 - 将 viewControllers 数组公开,然后使用 lastObject 调用该方法,或者应该如何设置?

【问题讨论】:

快速提问。你在小牛队还是优胜美地工作? @MacUserT Yosemite :) 【参考方案1】:

您的代码中有趣的是,您每次调用 IBAction 时都会分配/初始化一个新的视图控制器。每次调用 IBAction 方法时,您的视图可能都是全新的,但我认为您想要显示的视图数量有限。据我所知,只要您的 IBAction 方法很长,您的观点就会一直存在。该视图仍然存在,是因为您还没有刷新它。但是,调用不再在堆中的视图控制器内的方法(因为您离开了 IBAction 方法并且所有本地对象,例如您的视图控制器都从堆中获取而不是 ARC)会使应用程序崩溃,因为您引用未被使用或被其他东西使用的内存空间。

当您将视图添加到 viewcontrollers 数组时,为什么应用可以正常工作?我假设这个数组是一个已经在 AppDelegate 中启动的数组,现在您将具有强引用计数的视图控制器添加到 viewcontrollers 数组中。当您离开 IBAction 方法时,视图控制器仍然具有强引用,ARC 不会释放视图控制器。

这是正确的方法吗?嗯,它有效。我不认为它被认为是非常好的编程,因为您不会在离开方法后需要保持活动状态的方法中分配/初始化对象。最好在 AppDelegate 的 init、awakeFromNIB 或 windowDidLoad 方法中的某处分配和初始化视图控制器。您当前解决方案的问题是您正在创建一个无穷无尽的视图控制器数组,您只使用最后一个。在某个地方,您的程序会感受到这个非常长的相当重的对象(视图控制器)数组的负担,并且会耗尽内存。

希望这会有所帮助。

顺便说一句,这与您使用 Mavericks 还是 Yosemite 无关。我在想一个故事板解决方案,但这不能回答你的问题。

亲切的问候, Mac用户T

【讨论】:

以上是关于在 NSWindow 中呈现不同 NSViewController 的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

窗口NSWindow

在使用情节提要和 swift 时从 xib 打开 NSWindow

在 NSWindow 下方显示内容的最佳方式是啥?

NSLayoutConstraint 防止 NSWindow 调整大小

使用 NSDocument 和 NSWindow 跟踪 NSTextView 的变化

在 Swift 中打开一个关闭的 NSWindow 会导致应用程序崩溃