It is typical for Mac OS X apps to have preferences that apply seamlessly, and preferences dialogs don’t have “OK” or “Apply” button. I want to implement this behavior in my project, but I can’t decide when to apply/save changes made by user.
It’s quite clear that checkboxes and drop-downs can be saved immediately upon change, but when it comes to text fields, this approach seems questionable. For example, entering “programming.stackexchange.com” as host address will trigger 29 HDD writes, which seems just wrong. Moreover, in my simple implementation this will cause the entire settings file to be rewritten.
So is there any standard way to implement MacOS-like preferences?
7
One reasonable way to accomplish this is as follows:
- For an input type that has a discrete selection such as a check box, radio button, or list: save the setting as soon as the user makes the selection.
- For an input type that has freeform selection such as a text box: save the setting as soon as the input element loses focus or the dialog is dismissed. For longer text boxes (e.g. a rich text element that might contain complex data and a lot of it) it might make sense to save data every few seconds in addition to the previous criteria. In fact this is the same method used when writing questions and answers here on Stack Exchange.
It is important to be mindful that in addition to saving to persistent storage (i.e. hard disk) updating preferences may also trigger events in your application that update the UI elsewhere in the program. Handling these events may also consume resources such as CPU and memory. While not strictly addressing your question, it is closely related and worth thinking about while you implement a solution such as this.
If you’re using NSDefaults (or CFPreferences), you can update the default settings immediately. They get pushed to the background process cfprefsd
(short for Core Foundation PREFerenceS Daemon) which holds them in RAM and writes to disk at its leisure. Killing your app does not kill cfprefsd
, so the settings don’t get lost.
(Killing cfprefsd
, which I’ve actually seen people suggest as a way to keep it from overwriting a .plist that they’ve just modified behind its back, can wreak unbounded collateral damage. That would be a no-no.)
1