设置包值返回 nil
Settings bundle values returning nil
我在我的应用程序中添加了一个设置包,并且在 Xcode 它出现在我的项目树视图的根目录中。
Root.plist
文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>StringsTable</key>
<string>Root</string>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string>Service</string>
</dict>
<dict>
<key>Type</key>
<string>PSTextFieldSpecifier</string>
<key>Title</key>
<string>Hostname</string>
<key>Key</key>
<string>service_hostname</string>
<!-- and so on -->
当我在 iOS 上打开“设置”应用程序时,条目出现在底部,我可以完美地显示和编辑我的设置。
但是我无法从代码中检索这些值。这是我的代码:
static func loadSettings() {
let ud = NSUserDefaults.standardUserDefaults()
ud.synchronize()
Settings.hostName = ud.stringForKey("service_hostname")
// etc
}
我也尝试了 ud.objectForKey
和 ud.valueForKey
- 都 return nil
。
设置 Settings.hostName
后,Xcode 调试器报告它的值为 nil
,尽管我在“设置”应用中设置了明确的值。
我看到这个帖子 ( iPhone App : How to get default value from root.plist? ),其中有人发布了一大块 Objective-C 代码,这些代码手动将 Root.plist
文件直接加载到 NSMutableDictionary
并调用 NSUserDefaults.standardUserDefaults().registerDefaults
但这似乎是一个 hack(我无法让它在 Swift 中工作,因为编译器说 stringByAppendingPathComponent
不再存在)
为什么 NSUserDefaults
不从“设置”应用中选取设置?
显然是因为如果我在 plist
中的设置定义了默认值并且用户没有明确设置值,那么“设置”应用中显示的值将是 [=12] 中的默认值=] 文件,但是 NSUserDefaults
API 仍然 return nil
.
不幸的是,这意味着如果默认值有意义(例如默认的 Web 服务地址 URI:“http://www.example.com
”),它必须在我的项目中存在两次:作为 [=12 中的默认值=] 在我的程序代码中:
Root.plist:
<dict>
<key>Key</key> <string>mySettingKey</string>
<key>Title</key> <string>Some address</string>
<key>Type</key> <string>PSTextFieldSpecifier</string>
<key>DefaultValue</key> <string>http://www.example.com</string>
<key>IsSecure</key> <false />
<key>KeyboardType</key> <string>Alphabet</string>
</dict>
Program.swift:
let ud = NSUserDefaults.standardUserDefaults()
ud.synchronize()
var mySettingValue = ud.stringForKey("mySettingKey")
if mySettingValue == nil {
mySettingValue = "http://www.example.com"
}
真令人惊讶。
您应该注册您的默认设置,以便同步。 source from here
// Swift 3
var appDefaults = Dictionary<String, AnyObject>()
appDefaults["mySettingKey"] = "http://www.example.com" // Default Value
UserDefaults.standard.register(appDefaults)
UserDefaults.standard.synchronize()
let mySettingValue = UserDefaults.standard.string(forKey: "mySettingKey")
请记住,当您的应用程序使用设置包时,您还应该使用 registerDefaults:。由于您已经在设置包的 plist 中指定了默认值,您可能希望您的应用程序自动选择这些值。然而,事实并非如此。设置包中包含的信息仅由 iOS Settings.app 读取,而您的应用绝不会读取。为了让您的应用使用与 Settings.app 中所示相同的默认值,您必须手动将用户默认键及其默认值复制到单独的 plist 文件中,并将其注册到默认数据库,如上所示。
可以从 Settings.bundle
中获取默认值并添加到 UserDefaults。可以在 AppDelegate.swift
中从 didFinishLaunchingWithOptions
.
中调用以下函数
func setDefaultsFromSettingsBundle() {
//Read PreferenceSpecifiers from Root.plist in Settings.Bundle
if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"),
let settingsPlist = NSDictionary(contentsOf: settingsURL),
let preferences = settingsPlist["PreferenceSpecifiers"] as? [NSDictionary] {
for prefSpecification in preferences {
if let key = prefSpecification["Key"] as? String, let value = prefSpecification["DefaultValue"] {
//If key doesn't exists in userDefaults then register it, else keep original value
if UserDefaults.standard.value(forKey: key) == nil {
UserDefaults.standard.set(value, forKey: key)
NSLog("registerDefaultsFromSettingsBundle: Set following to UserDefaults - (key: \(key), value: \(value), type: \(type(of: value)))")
}
}
}
} else {
NSLog("registerDefaultsFromSettingsBundle: Could not find Settings.bundle")
}
}
您需要手动从 Settings.bundle 中读取默认值并将它们添加到 UserDefaults 注册域,这可以通过 UserDefaults.register()
完成。通过使用注册域,值保存在内存中(易失性),因此不需要调用 UserDefaults.synchronize()
。
Swift 4 和 5
这里有几行 Swift 可以完成工作:
// Register the default values from Settings.bundle
if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"),
let settingsRootDict = NSDictionary(contentsOf: settingsURL),
let prefSpecifiers = settingsRootDict["PreferenceSpecifiers"] as? [NSDictionary],
let keysAndValues = prefSpecifiers.map({ d in (d["Key"], d["DefaultValue"]) }) as? [(String, Any)] {
UserDefaults.standard.register(defaults: Dictionary(uniqueKeysWithValues: keysAndValues))
}
我在我的应用程序中添加了一个设置包,并且在 Xcode 它出现在我的项目树视图的根目录中。
Root.plist
文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>StringsTable</key>
<string>Root</string>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string>Service</string>
</dict>
<dict>
<key>Type</key>
<string>PSTextFieldSpecifier</string>
<key>Title</key>
<string>Hostname</string>
<key>Key</key>
<string>service_hostname</string>
<!-- and so on -->
当我在 iOS 上打开“设置”应用程序时,条目出现在底部,我可以完美地显示和编辑我的设置。
但是我无法从代码中检索这些值。这是我的代码:
static func loadSettings() {
let ud = NSUserDefaults.standardUserDefaults()
ud.synchronize()
Settings.hostName = ud.stringForKey("service_hostname")
// etc
}
我也尝试了 ud.objectForKey
和 ud.valueForKey
- 都 return nil
。
设置 Settings.hostName
后,Xcode 调试器报告它的值为 nil
,尽管我在“设置”应用中设置了明确的值。
我看到这个帖子 ( iPhone App : How to get default value from root.plist? ),其中有人发布了一大块 Objective-C 代码,这些代码手动将 Root.plist
文件直接加载到 NSMutableDictionary
并调用 NSUserDefaults.standardUserDefaults().registerDefaults
但这似乎是一个 hack(我无法让它在 Swift 中工作,因为编译器说 stringByAppendingPathComponent
不再存在)
为什么 NSUserDefaults
不从“设置”应用中选取设置?
显然是因为如果我在 plist
中的设置定义了默认值并且用户没有明确设置值,那么“设置”应用中显示的值将是 [=12] 中的默认值=] 文件,但是 NSUserDefaults
API 仍然 return nil
.
不幸的是,这意味着如果默认值有意义(例如默认的 Web 服务地址 URI:“http://www.example.com
”),它必须在我的项目中存在两次:作为 [=12 中的默认值=] 在我的程序代码中:
Root.plist:
<dict>
<key>Key</key> <string>mySettingKey</string>
<key>Title</key> <string>Some address</string>
<key>Type</key> <string>PSTextFieldSpecifier</string>
<key>DefaultValue</key> <string>http://www.example.com</string>
<key>IsSecure</key> <false />
<key>KeyboardType</key> <string>Alphabet</string>
</dict>
Program.swift:
let ud = NSUserDefaults.standardUserDefaults()
ud.synchronize()
var mySettingValue = ud.stringForKey("mySettingKey")
if mySettingValue == nil {
mySettingValue = "http://www.example.com"
}
真令人惊讶。
您应该注册您的默认设置,以便同步。 source from here
// Swift 3
var appDefaults = Dictionary<String, AnyObject>()
appDefaults["mySettingKey"] = "http://www.example.com" // Default Value
UserDefaults.standard.register(appDefaults)
UserDefaults.standard.synchronize()
let mySettingValue = UserDefaults.standard.string(forKey: "mySettingKey")
请记住,当您的应用程序使用设置包时,您还应该使用 registerDefaults:。由于您已经在设置包的 plist 中指定了默认值,您可能希望您的应用程序自动选择这些值。然而,事实并非如此。设置包中包含的信息仅由 iOS Settings.app 读取,而您的应用绝不会读取。为了让您的应用使用与 Settings.app 中所示相同的默认值,您必须手动将用户默认键及其默认值复制到单独的 plist 文件中,并将其注册到默认数据库,如上所示。
可以从 Settings.bundle
中获取默认值并添加到 UserDefaults。可以在 AppDelegate.swift
中从 didFinishLaunchingWithOptions
.
func setDefaultsFromSettingsBundle() {
//Read PreferenceSpecifiers from Root.plist in Settings.Bundle
if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"),
let settingsPlist = NSDictionary(contentsOf: settingsURL),
let preferences = settingsPlist["PreferenceSpecifiers"] as? [NSDictionary] {
for prefSpecification in preferences {
if let key = prefSpecification["Key"] as? String, let value = prefSpecification["DefaultValue"] {
//If key doesn't exists in userDefaults then register it, else keep original value
if UserDefaults.standard.value(forKey: key) == nil {
UserDefaults.standard.set(value, forKey: key)
NSLog("registerDefaultsFromSettingsBundle: Set following to UserDefaults - (key: \(key), value: \(value), type: \(type(of: value)))")
}
}
}
} else {
NSLog("registerDefaultsFromSettingsBundle: Could not find Settings.bundle")
}
}
您需要手动从 Settings.bundle 中读取默认值并将它们添加到 UserDefaults 注册域,这可以通过 UserDefaults.register()
完成。通过使用注册域,值保存在内存中(易失性),因此不需要调用 UserDefaults.synchronize()
。
Swift 4 和 5
这里有几行 Swift 可以完成工作:
// Register the default values from Settings.bundle
if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"),
let settingsRootDict = NSDictionary(contentsOf: settingsURL),
let prefSpecifiers = settingsRootDict["PreferenceSpecifiers"] as? [NSDictionary],
let keysAndValues = prefSpecifiers.map({ d in (d["Key"], d["DefaultValue"]) }) as? [(String, Any)] {
UserDefaults.standard.register(defaults: Dictionary(uniqueKeysWithValues: keysAndValues))
}