简体   繁体   English

Swift 4 设置包,获取默认值

[英]Swift 4 Settings Bundle, get defaults

I created a settings bundle with about 8 toggle switches.我创建了一个包含大约 8 个切换开关的设置包。 What I am trying to do it get the default values from the settings bundle.我正在尝试从设置包中获取默认值。 Currently right now I have these two methods:目前我有这两种方法:

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)
    }

and I am calling these methods in my viewDidLoad我在 viewDidLoad 中调用这些方法

override func viewDidLoad() {
        super.viewDidLoad()
        registerSettingsBundle()
        updateDisplayFromDefaults()
    }

However this does not get me the default values (which are all true, but they all return false).然而,这并没有让我得到默认值(它们都是真的,但它们都返回假)。 This works and gives me the correct values if I close down the app, open settings, adjust the settings and re-open the app.如果我关闭应用程序,打开设置,调整设置并重新打开应用程序,这会起作用并为我提供正确的值。 Is there away of getting the default settings?有没有获得默认设置? I went the route of reading the plist, but if I change the settings in my settings bundle, it would not take effect.我走的是阅读plist的路线,但是如果我更改设置包中的设置,它将不会生效。

For the sake of the demonstration let's assume that you have two switches in the settings bundle.为了演示起见,我们假设您在设置包中有两个开关。 One with the default value set to YES and one with the default value set to NO .一种将默认值设置为YES ,另一种将默认值设置为NO

Settings.bundle 内容

If you want to be able to access default values defined in the Settings.bundle from the UserDefaults in your app you have to register them first.如果您希望能够从应用程序中的UserDefaults访问Settings.bundle定义的默认值,则必须先注册它们。 Unfortunately, iOS won't do it for you and you have to take care of it by yourself.不幸的是,iOS 不会为你做这件事,你必须自己照顾它。

The following method scans the Root.plist associated with the Settings.bundle and registers the default values for the identifiers of your preferences.以下方法扫描与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)
}

I recommend running it as early as possible.我建议尽早运行它。 You will be sure that the defaults are there for all parts of your app.您将确保应用程序的所有部分都有默认值。

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
}

this does not get me the default values (which are all true, but they all return false)这不会让我得到默认值(这些都是真的,但它们都返回假)

Looks like you have a toggle switch which displays as ON in the setting bundle and when you read bundle you get all the false value.看起来您有一个切换开关,它在设置包中显示为 ON,当您读取包时,您会得到所有错误值。

If this is the case then you are missing something here.如果是这种情况,那么您在这里遗漏了一些东西。

In setting bundle(Root.plist) we have "Default Value" field which is nothing to do with the actual default value of toggle switch.在设置 bundle(Root.plist) 中,我们有“默认值”字段,它与切换开关的实际默认值无关。 This is just a visual indicator to switch.这只是一个切换的视觉指示器。 You may have "Default value" set as "YES" in plist but when you try to read the value you will end up getting false .您可能在 plist 中将“默认值”设置为“YES”,但是当您尝试读取该值时,您最终会得到false

在此处输入图片说明

Here I have set Default Value for Reminder in Root.plist as YES and for Update NO So that when app launch it shows as above.在这里,我已将 Root.plist 中提醒的默认值设置为YES ,将更新设置为NO ,以便在应用程序启动时显示如上。

But when I tried to read these defaults - it gives both as false .但是当我尝试阅读这些默认值时 - 它给出了两者都为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 Update 的默认值 - false 提醒的默认值 - false

Now, if you want to sync these values - default value in Root.plist and value of default - then you have to set it programmatically.现在,如果你想同步这些值——Root.plist 中的默认值和默认值——那么你必须以编程方式设置它。

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

Here in my Root.plist I have default value as YES and also when viewDidload I set this preference value as true .在我的 Root.plist 中,我的默认值为YES ,并且在 viewDidload 时我将此首选项值设置为true When I run it gives me当我运行它给我

Default value of Reminder - true提醒的默认值 - true

And this is how my Root.plist looks.这就是我的 Root.plist 的样子。

在此处输入图片说明

Hope it helps.希望它有帮助。

Add notification for UserDefaults.didChangeNotification like below: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)
}

Here's an answer based on @Kamil (many thanks for that) that doesn't rely on NSDictionary and uses PropertyListSerialization .这是基于@Kamil(非常感谢)的答案,它不依赖于NSDictionary并使用PropertyListSerialization

Swift 5斯威夫特 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)
}

So for a Root.plist like this:所以对于这样的Root.plist

根目录

... the defaultsToRegister would be: ... defaultsToRegister将是:

默认注册

There's also the new compactMapValues() API in Swift 5 that may or may not be helpful here. Swift 5中还有新的compactMapValues() API,在这里可能有用也可能没有帮助。

I am having a little bit of trouble following exactly what you're asking, but it sounds like you've created a settings bundle plist that specifies that some defaults are "true" if undefined (so that if a user hasn't set them they default to true).我在完全按照您的要求进行操作时遇到了一些麻烦,但听起来您已经创建了一个设置包 plist,它指定如果未定义某些默认值是“真”(这样如果用户没有设置它们他们默认为真)。 But I think when you do:但我认为当你这样做时:

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

...there is no way for this code to know that "unset" should evaluate to "true" instead of "false". ...此代码无法知道“未设置”应评估为“真”而不是“假”。 You could use defaults.object(forkey: "update_lot") instead and if that returns an object, get the boolean value of that object (or just call defaults.bool at that point), but if it returns nil assume that it's true.您可以使用defaults.object(forkey: "update_lot")代替,如果它返回一个对象,则获取该对象的布尔值(或者在该点调用defaults.bool ),但如果它返回 nil 则假设它是真的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM