Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSViewController User Interface State Restoration

Summary:

What's the proper way to save/restore the state of an NSSearchField in my NSViewController using the built-in user interface preservation mechanism of Cocoa?

Details:

I'm working on my first macOS app and I'm having a little trouble with state restoration for my user interface. So far I have it working to the point where the encodeRestorableState(with:) and restoreState(with:) methods are called in my NSViewController subclass.

I have an NSSearchField in my view controller and I want to save/restore the state of the search field including its text, any selection, the cursor position, and whether it is currently in focus or not.

If I use the following code, the text is properly saved and restored:

override func encodeRestorableState(with coder: NSCoder) {     super.encodeRestorableState(with: coder)      coder.encode(searchField.stringValue, forKey: "searchText") }  override func restoreState(with coder: NSCoder) {     super.restoreState(with: coder)      if let searchText = coder.decodeObject(forKey: "searchText") as? String {         searchField.stringValue = searchText     } } 

Obviously I can add more code to save/restore the search field's selection and cursor position, etc.

My real question is, is there a better, proper, more automatic way to save and restore the search field's state? Or is it required that I write my own code for each attribute of the search field I wish to save?

I tried using:

searchField.encodeRestorableState(with: coder) 

and:

searchField.restoreState(with: coder) 

in the two above methods but that didn't result in anything appearing in the search field when my app was restarted.

I also implemented:

override class func restorableStateKeyPaths() -> [String] {     var keys = super.restorableStateKeyPaths()     keys.append("searchField.stringValue")      return keys } 

where "searchField" is the name of the NSTextField outlet property in my view controller. This method is called when my app is launched but the text was not restored in the search field.

This view controller is created from a storyboard. The view controller's identifier is set. The search field's identifier is set as well. This view controller is a child view controller of another view controller.

I've read through the User Interface Preservation section of the "The Core App Design" document but it's unclear on how a view controller's views are saved/restored and how much of this is automatic versus manual.

Supporting OSX 10.12 and 10.11. Objective-C or Swift in any answers is fine.

like image 484
rmaddy Avatar asked Dec 12 '16 15:12

rmaddy


1 Answers

To achieve aforementioned effect let's create NSSearchField and a custom class named RestoredWindow containing just one property:

import Cocoa  class RestoredWindow: NSWindow {      override class var restorableStateKeyPaths: [String] {         return ["self.contentViewController.searchField.stringValue"]     } } 

Assign this custom class to Window Controller in Identity Inspector.

Next, let's bind searchField.stringValue property to ViewController in Value section of Bindings Inspector.

import Cocoa  class ViewController: NSViewController {      @IBOutlet weak var searchField: NSSearchField!      override func viewDidLoad() {         super.viewDidLoad()     } } 

After this, make sure you haven't checked Close windows when quitting an app option in your System Preferences -> General tab.

Now, entered text in NSSearchField restored after quitting and launching the app again.

P.S.

I've tried the same way as you but failed too. This approach doesn't work for me:

override func encodeRestorableState(with coder: NSCoder) {     coder.encode(searchField.stringValue, forKey: "restore")     super.encodeRestorableState(with: coder) }  override func restoreState(with coder: NSCoder) {        if let state = coder.decodeObject(forKey: "restore") as? NSSearchField {         searchField.stringValue = state     }     super.restoreState(with: coder) } 
like image 110
Andy Jazz Avatar answered Sep 19 '22 02:09

Andy Jazz