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

Correct method to present a different NSViewController in NSWindow

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

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

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

我为 AppDelegate 的 NSButton 设置了 target/action,这里是我调用该方法以显示新视图控制器的地方:

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

这确实有效 - 它呈现了新的视图控制器的视图。但是,如果我随后单击该视图中的任何按钮,该视图具有驻留在其视图控制器 class 中的 target/action 设置,应用程序会立即崩溃。

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

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

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

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

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

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

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

希望对您有所帮助。

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

亲切的问候, MacUserT