Edit: my original question, below, assumes there is a secret copy (a cache) of the system preferences settings. I have since learned that is not the case. However, my problem still needed a solution, which I have found and also posted, below. No special Objective-C process is needed. /edit.

I want to use the defaults write command to change a checkbox in System Preferences. E.g:

defaults write ./com.apple.speech.synthesis.general.prefs TimeAnnouncementPrefs -dict-add TimeAnnouncementsEnabled -bool YES

However, the OS caches the preference files, so the defaults command has no effect until the cache is updated. The System Preferences app updates the cache after a change is made in its UI -- so it is possible. Some people have suggested sudo killall cfprefsd but that does not work in Big Sur.

Elsewhere, user3439894 has posted a good AppleScript that manipulates the System Preferences UI. But such UI manipulation does not work when the Screen Saver is running.

I'd like to figure out how the System Preferences app manages to update the preferences cache. Doing strings of the System Preferences app (at /System/Applications/System\ Preferences.app/Contents/macOS/System\ Preferences) shows a method updateCacheFileWithPrefPane: that might do the job, but I don't know how to call that method. The method, whatever it is, is private, but I only need this for myself (not a public app).

Is it possible to use dtrace or dtruss to figure out what the System Preferences app is doing to signal the OS to update its cache for a particular checkbox? I want to write an Objective-C program to do the same thing, but I need a dtrace/dtruss expert to help me.

有帮助吗?

解决方案 2

I have a solution. The secret is to manipulate the macOS SpeechSynthesisServer.app after changing the Time Announce preference setting using defaults write. There is no saved copy of the settings, and no special Objective-C process is needed. (Dale Sedivec helped via email after I read his June 2019 post about System Preferences at assert.cc).

To turn "Announce the time:" ON:

defaults write ./com.apple.speech.synthesis.general.prefs TimeAnnouncementPrefs -dict-add TimeAnnouncementsEnabled -bool YES   
open /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesisServer.app

To turn "Announce the time:" OFF:

defaults write ./com.apple.speech.synthesis.general.prefs TimeAnnouncementPrefs -dict-add TimeAnnouncementsEnabled -bool NO    
killall SpeechSynthesisServer # takes effect after 30 seconds

In both cases, re-launching System Preferences causes the System Preferences GUI to show the new Time Announce checkbox setting. The launching or killing of SpeechSynthesisServer.app causes the OS to respect the new setting. I'm using Keyboard Maestro to do this.

其他提示

macOS uses NSUserDefaults to implement defaults. It offers an Objective-C interface and is part of the Foundation framework used by System Preferences and most applications to deal with preferences.

Caching of defaults is handled by the framework and the calling application is not expected to know about or manipulate the cache. See NSUserDefaultsDidChangeNotification and Key Value Observation (KVO) for how applications can track changes.

CFPreferencesSynchronize

NSUserDefaults itself is implemented with the C based CFPreferences set of functions, found in CoreFoundation framework.

In this layer, the documentation for the function CFPreferencesSynchronize reads:

This function is the primitive synchronize mechanism for the higher level preference function CFPreferencesAppSynchronize it writes updated preferences to permanent storage, and reads the latest preferences from permanent storage.

Only the exact domain specified is modified. Note that to modify “Any User” preferences requires root privileges (or Admin privileges prior to OS X v10.6)—see Authorization Services Programming Guide.

Do not use this function directly unless you have a specific need. All arguments must be non-NULL. Do not use arbitrary user and host names, instead pass the pre-defined constants.

macOS 11.2 is partly open source. Be sure to check if defaults is part of the open section. This may be useful in determining which domains and suites the preferences affect.

许可以下: CC-BY-SA归因
不隶属于 apple.stackexchange
scroll top