Swift 4 个设置包,获取默认值

Swift 4 Settings Bundle, get defaults

我创建了一个包含大约 8 个拨动开关的设置包。我正在尝试做的是从设置包中获取默认值。目前我有这两种方法:

func registerSettingsBundle(){
        let appDefaults = [String:AnyObject]()
        UserDefaults.standard.register(defaults: appDefaults)
        UserDefaults.standard.synchronize()
    }

    func updateDisplayFromDefaults(){
        let defaults = UserDefaults.standard
        let update_lot = defaults.bool(forKey: "update_lot")
        print(update_lot)
    }

并且我在我的 viewDidLoad

中调用了这些方法
override func viewDidLoad() {
        super.viewDidLoad()
        registerSettingsBundle()
        updateDisplayFromDefaults()
    }

然而,这并没有给我默认值(它们都是真的,但它们都是 return 假的)。如果我关闭应用程序、打开设置、调整设置并重新打开应用程序,这会起作用并为我提供正确的值。是否可以获取默认设置?我去了阅读 plist 的路线,但是如果我更改我的设置包中的设置,它不会生效。

UserDefaults.didChangeNotification 添加通知,如下所示:

override func viewDidLoad() {
    super.viewDidLoad()
    registerSettingsBundle()
    NotificationCenter.default.addObserver(self, selector: #selector(updateDisplayFromDefaults), name: UserDefaults.didChangeNotification, object: nil)
    updateDisplayFromDefaults()
}
func registerSettingsBundle(){
    let appDefaults = [String:AnyObject]()
    UserDefaults.standard.register(defaults: appDefaults)
    UserDefaults.standard.synchronize()
}

func updateDisplayFromDefaults(){
    let defaults = UserDefaults.standard
    let update_lot = defaults.bool(forKey: "update_lot")
    print(update_lot)
}

我在完全按照您的要求进行操作时遇到了一些麻烦,但听起来您已经创建了一个设置包 plist,它指定某些默认值是 "true" 如果未定义(这样如果用户没有设置它们,它们默认为 true)。但我认为当你这样做时:

let update_lot = defaults.bool(forKey: "update_lot")

...此代码无法知道 "unset" 的计算结果应为 "true" 而不是 "false"。您可以改用 defaults.object(forkey: "update_lot"),如果 returns 是一个对象,则获取该对象的布尔值(或者只是在那个时候调用 defaults.bool),但如果 returns nil假设这是真的。

this does not get me the default values (which are all true, but they all return false)

看起来你有一个切换开关,它在设置包中显示为 ON,当你读取包时,你会得到所有错误的值。

如果是这种情况,那么您在这里遗漏了一些东西。

在设置 bundle(Root.plist) 中,我们有 "Default Value" 字段,它与拨动开关的实际默认值无关。这只是一个切换的视觉指示器。 您可能在 plist 中将 "Default value" 设置为 "YES",但是当您尝试读取该值时,您最终会得到 false

这里我设置了 默认值 用于 Root.plist 中的提醒 YES更新 这样当应用程序启动时它显示如上。

但是当我尝试读取这些默认值时 - 它给出的都是 false.

func getDefaults() {        
    let stanDefaults = UserDefaults.standard
    print("Default value of Update - \(stanDefaults.bool(forKey: "update_lot_pref"))")
    print("\nDefault value of Reminder - \(stanDefaults.bool(forKey: "reminder_pref"))")
}

Default value of Update - false Default value of Reminder - false

现在,如果您想要同步这些值 - Root.plist 中的默认值和默认值 - 那么您必须以编程方式进行设置。

func setApplicationDefault() {
    let stanDefaults = UserDefaults.standard
    let appDefaults = ["reminder_pref": true]
    stanDefaults.register(defaults: appDefaults)
    stanDefaults.synchronize()
}

在我的 Root.plist 中,我的默认值为 YES 并且当 viewDidload 时,我将此首选项值设置为 true .当我 运行 它给了我

Default value of Reminder - true

这就是我的 Root.plist 的样子。

希望对您有所帮助。

为了演示起见,我们假设您在设置包中有两个开关。一种将默认值设置为 YES,另一种将默认值设置为 NO.

如果您希望能够从应用中的 UserDefaults 访问 Settings.bundle 中定义的默认值,您必须先注册它们。很遗憾,iOS 不会为您代劳,您必须自己处理。

以下方法扫描与 Settings.bundle 关联的 Root.plist 并为您的首选项标识符注册默认值。

func registerDefaultsFromSettingsBundle()
{
    let settingsUrl = Bundle.main.url(forResource: "Settings", withExtension: "bundle")!.appendingPathComponent("Root.plist")
    let settingsPlist = NSDictionary(contentsOf:settingsUrl)!
    let preferences = settingsPlist["PreferenceSpecifiers"] as! [NSDictionary]
    
    var defaultsToRegister = Dictionary<String, Any>()
    
    for preference in preferences {
        guard let key = preference["Key"] as? String else {
            NSLog("Key not found")
            continue
        }
        defaultsToRegister[key] = preference["DefaultValue"]
    }
    UserDefaults.standard.register(defaults: defaultsToRegister)
}

我推荐运行 尽早。您将确保您的应用程序的所有部分都有默认值。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
    registerDefaultsFromSettingsBundle()
    
    let one = UserDefaults.standard.bool(forKey: "switch_one")
    let two = UserDefaults.standard.bool(forKey: "switch_two")
    
    NSLog("One: \(one), Two: \(two)")
    
    return true
}

这是一个基于@Kamil 的答案(非常感谢),它不依赖 NSDictionary 并使用 PropertyListSerialization.

Swift 5

func registerDefaultsFromSettingsBundle() {
    let settingsName                    = "Settings"
    let settingsExtension               = "bundle"
    let settingsRootPlist               = "Root.plist"
    let settingsPreferencesItems        = "PreferenceSpecifiers"
    let settingsPreferenceKey           = "Key"
    let settingsPreferenceDefaultValue  = "DefaultValue"

    guard let settingsBundleURL = Bundle.main.url(forResource: settingsName, withExtension: settingsExtension),
        let settingsData = try? Data(contentsOf: settingsBundleURL.appendingPathComponent(settingsRootPlist)),
        let settingsPlist = try? PropertyListSerialization.propertyList(
            from: settingsData,
            options: [],
            format: nil) as? [String: Any],
        let settingsPreferences = settingsPlist[settingsPreferencesItems] as? [[String: Any]] else {
            return
    }

    var defaultsToRegister = [String: Any]()

    settingsPreferences.forEach { preference in
        if let key = preference[settingsPreferenceKey] as? String {
            defaultsToRegister[key] = preference[settingsPreferenceDefaultValue]
        }
    }

    UserDefaults.standard.register(defaults: defaultsToRegister)
}

所以对于这样的 Root.plist

... defaultsToRegister 将是:

还有 the new compactMapValues() API in Swift 5 可能有用也可能没用。