4

可以制作 NSWindows,restorable以便在应用程序启动之间保留它们的配置。

https://developer.apple.com/documentation/appkit/nswindow/1526255-restorable

应在启动周期之间保留 Windows,以保持用户界面的连续性。在随后的启动周期中,系统会尝试重新创建窗口并将其配置恢复到保留状态。配置数据根据需要更新并由系统自动保存。

在一个新的 macOS 项目中,Storyboard 上的 NSWindowrestorable默认为:

Xcode 中的可恢复复选框


我的问题是在 NSWindow 中嵌入 NSTabViewController 时出现的。

NSTabViewController

NSTabViewrestorable自动继承窗口的状态,无需添加代码。

这使得选定的选项卡在应用程序启动之间保持不变。我不想要那个。我希望它始终默认为索引 0。如果所选选项卡已恢复,尝试以编程方式选择选项卡会viewDidLoad产生意外结果。


如何强制将某些 AppKit UI 元素从 NSWindow 状态恢复中排除?

我希望选项卡视图不可恢复。

但我保留其他可恢复的好处,例如恢复之前设置的窗口大小。

如何从 NSWindow 状态恢复中排除单个视图?

4

2 回答 2

1

AFAIK,您不能排除 UI 的某个部分可恢复。对于所有元素,它是 ON 或 OFF 的事情。这就是为什么我很少使用 Apple 自己的可恢复性 API,因为它们通常不可靠。我总是自己进行修复以获得您需要的精细控制。然而,对于更简单的窗口,我让系统进行恢复。

在此序言之后,为了真正回答您的问题,我很少使用viewDidLoad()设置任何窗口,因为您发现这会产生一些令人讨厌的后果(例如,窗口可能还不存在!)。我总是这样做viewWillAppear()。为此,您需要设置以下内容:

  1. 您需要在您的父级实例中拥有一个 ivar(我们称之为tabViewController)(我们称之为 NSViewMainController)NSTabViewControllerNSViewController

  2. 在 NSViewMainController 中覆盖prepare(for segue: NSStoryboardSegue, sender: Any?)并设置 NSTabViewController 及其NSViewController子项,如下所示:

    override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
       // set up the tabViewController ivar
       self.tabViewController = segue.destinationController as? NSTabViewController
    
       // set up the child NSViewControllers if you need to access them via their parent (otherwise this step is not needed)
       if let childControllers = tabViewController?.children {
          for controller in childControllers {
             if let controller = controller as? NSViewController1 {
                childController1 = controller
             }
             else if let controller = controller as? NSViewController2 {
                childController2 = controller
             }
             else if let controller = controller as? NSViewController3 {
                childController3 = controller
             }
          }
       }
    }
    
  3. 覆盖 NSViewMainController 的 viewWillAppear() ,然后设置所需的 tabView:

    guard let controller = tabViewController else { return }
    controller.selectedTabViewItemIndex = 0
    

主要警告:但请注意 viewWillAppear()... 与 viewDidLoad() 不同,此覆盖可以多次调用,因此您需要在代码中考虑到这一点并做出适当的反应。

于 2020-05-07T04:12:06.420 回答
1

状态恢复的关键是 NSResponder 方法restoreStateWithCoder:

此方法是窗口恢复系统的一部分,在启动时调用以恢复响应者对象的视觉状态。默认实现除了特定的子类(例如 NSView 和 NSWindow)覆盖它并保存重要的状态信息之外什么都不做。因此,如果你重写了这个方法,你应该总是在你的实现中调用 super。

https://developer.apple.com/documentation/appkit/nsresponder/1526253-restorestate

因此,要不恢复某个控制,请将此方法设为无操作。

它说您“应该始终调用 super”,但这会恢复窗口状态。因此,如果您不想恢复窗口,请不要调用 super。

对于选项卡视图,显然必须在 NSTabView(子类)本身中完成。在其他视图中,在视图控制器上覆盖此方法可能会起作用。

class SomeTabView: NSTabView {
    
    override func restoreState(with coder: NSCoder) {
        // Do NOT restore state
    }
    
}
于 2020-05-08T23:42:30.993 回答