老谭笔记

修改其它程序的defaults文件

在iOS和Mac开发的程序中,我们常用NSUserDefaults来保存一些配置信息,我们都知道这是一种基于Plist文件的存储,并且最终保存的信息存放在/Library/Preferences/或~/Library/Preferences/目录之下,以BundleID命名的plist之中。

在Mac下我们通过修改系统程序配置来开启一些隐藏设置,如开启Finder显示隐藏文件功能,就需要去修改Finder程序的配置文件的AppleShowAllFiles这个键值,你可能想到直接修改~/Library/Preferences/com.apple.finder.plist文件来达到目的,但是由于NSUserDefaults会有一套缓存机制,所以对于正在运行的程序你直接修改这个文件极有可能是不会成功的,当然如果Finder未启动时,你这样做就是OK的,但像Finder和Dock这样的程序是通过launchd启动的,所以它是一直处于运行状态,你就只能另辟蹊径了。

在OSX系统下,有一个defaults的工具,使用它就可以很方便的去修改这个值并且保证有效,比如上面提到的开启Finder显示隐藏文件功能,我们可以这样:

1
2
3
4
//设置Finder的配置项值
system("defaults write com.apple.finder AppleShowAllFiles -bool true");
//重启Finder
system("killall Finder");

但使用defaults有很大的局限性,比如想读取或修改结构复杂的键值(NSArray和NSDictionary),恰好我在一个项目中就遇上这样的需求,通过查找资料我发现有更加方便的的API,那就是Carbon接口中的CFPreferences相关方法,由于它是原生的方法,不直接依赖于其它程序,所以是一个非常好的选择,上面的代码修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
//读取当前的值,读取前先同步
CFPreferencesAppSynchronize(dockID);
CFBooleanRef valueRef = CFPreferencesCopyAppValue(key, dockID);
CFBooleanGetValue(valueRef);
//设置新的值,修改后同步
CFPreferencesSetAppValue(CFSTR("AppleShowAllFiles"),
CFBooleanGetValue(valueRef)?kCFBooleanFalse:kCFBooleanTrue,
dockID);
CFPreferencesAppSynchronize(dockID);
//重启Finder
system("killall Finder");

以上测试代码Demo下载:PreferencesDemo.zip