Settings bundle values returning nil

后端 未结 4 1588
青春惊慌失措
青春惊慌失措 2021-01-04 22:25

I added a Settings bundle to my app and in Xcode it appears in the root of my project tree view.

The Root.plist file looks like this:

&l         


        
相关标签:
4条回答
  • 2021-01-04 23:04

    Apparently the cause is that if my settings in the plist have defaults defined and the user has not explicitly set a value, then the value displayed in the Settings app will be the defaults from the plist file, however the NSUserDefaults API will still return nil.

    Unfortunately this means that if the default value is meaningful (such as a default web-service address URI: "http://www.example.com") it must exist twice in my project: as a default in the plist and in my program code:

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

    That's surprising.

    0 讨论(0)
  • 2021-01-04 23:06

    You need to manually read the default values from Settings.bundle and add them to the UserDefaults registration domain, which can be done with UserDefaults.register(). By using the registration domain, the values are held in memory (volatile), so calling UserDefaults.synchronize() is not needed.

    Swift 4 and 5

    Here's a few lines of Swift that will get the job done:

    // 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))
    }
    
    0 讨论(0)
  • 2021-01-04 23:11

    Default values can be taken from Settings.bundle and added to UserDefaults. Following function can be called in AppDelegate.swift from 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")
        }
    }
    
    0 讨论(0)
  • 2021-01-04 23:15

    You should register your defaults so that it will sync up. 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")
    

    Keep in mind that you should also use registerDefaults: when your app uses a Settings Bundle. Since you already specified default values inside the settings bundle’s plist, you may expect that your app picks these up automatically. However, that is not the case. The information contained in the settings bundle is only read by the iOS Settings.app and never by your app. In order to have your app use the same defaults as shown inside the Settings.app, you have to manually copy the user defaults keys and their default values into a separate plist file and register it with the defaults database as shown above.

    0 讨论(0)
提交回复
热议问题