代码之家  ›  专栏  ›  技术社区  ›  Andy Jazz

通过Swift在Cocoa中实现UI保存/恢复机制

  •  1
  • Andy Jazz  · 技术社区  · 6 年前

    我想挽救 Check Box ,退出应用程序,然后再次启动macOS应用程序以查看我的 复选框 。但我的应用程序的UI中没有还原状态。

    我做错了什么?

    import Cocoa
    
    class ViewController: NSViewController {
    
        @IBOutlet weak var tick: NSButton!
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func encodeRestorableState(with coder: NSCoder) {
            super.encodeRestorableState(with: coder)
            coder.encode(tick.state, forKey: "")
        }
    
        override func restoreState(with coder: NSCoder) {
            super.restoreState(with: coder)       
            if let state = coder.decodeObject(forKey: "") as? NSControl.StateValue {
                tick.state = state
            }
        }
    }
    
    3 回复  |  直到 6 年前
        1
  •  3
  •   James Bucanek    6 年前

    据我所知,这是实现窗口和/或其内容的自定义UI状态恢复所需的最小值。

    在本例中,我有一个带有复选框的窗口,该复选框的状态表示我想在重新启动应用程序时恢复的一些自定义视图状态。

    该项目包含一个带有单个复选框按钮的窗口。按钮的值绑定到 myState 窗口的内容视图控制器的属性。因此,从技术上讲,这是一个复选框控件这一事实是无关紧要的;我们实际上要保护和恢复 我的国家 属性(UI自行处理)。

    为了让这一切顺利进行 restorable 属性设置为 true (在窗口对象检查器中)并为窗口指定了标识符( "PersistentWindow" )。 NSWindow 是子类的( PersistentWindow )子类实现 restorableStateKeyPaths 所有物此属性列出要保留/恢复的自定义属性。

    注意:如果可以根据符合键值的属性路径列表定义UI状态恢复,那么这是(到目前为止)最简单的解决方案。如果没有,则必须实施 encodeRestorableState / restoreState 并负责呼叫 invalidateRestorableState

    以下是自定义窗口类:

    class PersistentWindow: NSWindow {
    
        // Custom subclass of window the perserves/restores UI state
    
        // The simple way to preserve and restore state information is to just declare the key-value paths
        //  of the properties you want preserved/restored; Cocoa does the rest
        override class var restorableStateKeyPaths: [String] {
           return [ "self.contentViewController.myState" ]
           }
    
        // Alternatively, if you have complex UI state, you can implement these methods
    //  override func encodeRestorableState(with coder: NSCoder) {
    //      // optional method to encode special/complex view state here
    //  }
    //  
    //  override func restoreState(with coder: NSCoder) {
    //      // companion method to decode special/complex view state
    //  }
    
    }
    

    下面是内容视图控制器的(相关部分)

    class ViewController: NSViewController {
    
        @objc var myState : Bool = false
    
        blah, blah, blah
    }
    

    (我将此构建为一个可可应用程序项目,如果有人告诉我可以将其上载到哪里,我可以将其上载。)

        2
  •  3
  •   Ceylo    5 年前

    实际上你不需要通过 restorableStateKeyPaths /KVO/KVC,如果您不想的话。

    我被困在和你一样的状态 encodeRestorableState() & restoreState() 方法未被调用,但找到了缺少的内容。

    1. 系统内首选项(&T);一般情况下,请确保未选中“退出应用程序时关闭窗口”。
    2. 确保 NSWindow 包含视图在IB中启用了“可恢复”行为。 NSWindow restorable
    3. 确保您的 NSViewController 设置了“还原ID”。 View controller restoration ID
    4. 你的 NSViewController 除非你打电话,否则不会被编码 invalidateRestorableState() .您需要在每次出现状态时调用此 NSViewController 这些更改和您想要保存的内容。
    5. NSViewController 还原后,关闭应用程序时,其状态将不会再次编码。这将导致在重新启动应用程序时无法恢复自定义状态。我找到的最简单的方法就是 invalidateRestorableState() 在里面 viewDidLoad() ,以便始终保存该状态。

    在完成所有这些之后,我甚至不需要额外实现 NSApplicationDelegate NSWindowRestoration 协议方法。所以国家恢复了 NSViewController 非常独立。只有外部财产才可恢复 NSWindow(NSWindow)

        3
  •  1
  •   de.    3 年前

    在为这个问题浪费了几个小时的生命后,我终于让它起作用了。其他答案中的一些信息是有用的,一些是缺失的,一些是不必要的。

    下面是我基于一个新的Xcode 13项目的最小示例:

    1. 在AppDelegate中添加 (其他示例中缺少此项) :
      func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { return true }
      
    2. 在ViewController中添加:
      @objc var myState : Bool = false
      
      override class var restorableStateKeyPaths: [String] {
         return [ "myState" ]
      }
      
    3. 设置一些UI并将其绑定到 myState 看看发生了什么
    4. 确保系统首选项>;常规(>);未选中“退出应用时关闭窗口”

    我认为 没有 需要做的事情:

    • 创建自定义窗口子类
    • 设置自定义还原id
    • 仅使用Xcode启动/停止就可以正常工作