简体   繁体   中英

Returning the value of a settings bundle switch in Swift / Xcode 6

I have difficulties returning the value of a stored boolean key.

My root.plist looks like this:

在此处输入图片说明

I've got this in AppDelegate:

    let a = NSUserDefaults.standardUserDefaults().boolForKey("sound")

    if a { // This is where it breaks
        println("sound is on")
    }

Any ideas what I'm doing wrong?

First you should register your defaults so everything is sync'd up and defaults are assigned. Then you'll know a value exists. These values are not automatically synchronized on startup.

var appDefaults = Dictionary<String, AnyObject>()
appDefaults["sound"] = false
NSUserDefaults.standardUserDefaults().registerDefaults(appDefaults)
NSUserDefaults.standardUserDefaults().synchronize()

let a = NSUserDefaults.standardUserDefaults().boolForKey("sound")

if a { // This is where it breaks
    println("sound is on")
}

Below is an excerpt from a relevant article.

When Your App Uses a Settings Bundle

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.

And HERE is the relevant discussion directly from Apple.

Registering Defaults

Discussion

If there is no registration domain, one is created using the specified dictionary, and NSRegistrationDomain is added to the end of the search list. The contents of the registration domain are not written to disk; you need to call this method each time your application starts. You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file.

Use this:

    var myDict: NSDictionary?
// Read from the Configuration plist the data to make the state of the object valid.
    if let path = NSBundle.mainBundle().pathForResource("root", ofType: "plist") {
        myDict = NSDictionary(contentsOfFile: path)
    }

    // Set the values to init the object
    if let dict = myDict {
        if let a = dict["sound"] as? Bool {
         if a { 
            println("sound is on")
          }
        }
    }

I came this post as I had the same issue today, and wasn't very satisfied with this note:

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.

I thought there must be a more DRY solution, so I made the following extension. It iterates through the Settings.bundle's plists (including Child plists) and registers any DefaultValues it finds. Also available in this gist .

extension UserDefaults {

    static func syncSettingsBundle() {
        if let bundlePath = Bundle.main.path(forResource: "Settings", ofType: "bundle"),
            let plistPath = URL(string: bundlePath)?.appendingPathComponent("Root.plist").absoluteString {

            let defaultDefaults = UserDefaults.defaultsForPlist(path: plistPath, defaults: [:])
            UserDefaults.standard.register(defaults: defaultDefaults)
        }
    }

    static private func defaultsForPlist(path: String, defaults: [String: Any]) -> [String: Any] {
        var mutableDefaults = defaults
        if let plistXML = FileManager.default.contents(atPath: path) {
            do {
                let plistData = try PropertyListSerialization.propertyList(from: plistXML,
                                                                           options: .mutableContainersAndLeaves,
                                                                           format: nil) as! [String:AnyObject]
                if let prefs = plistData["PreferenceSpecifiers"] as? Array<[String: Any]> {
                    prefs.forEach { (pref: [String : Any]) in
                        if let key = pref["Key"] as? String,
                            let value = pref["DefaultValue"] {
                            mutableDefaults[key] = value
                        } else if let type = pref["Type"] as? String,
                            type == "PSChildPaneSpecifier",
                            let file = pref["File"] as? String,
                            let childPath = URL(string: path)?
                                .deletingLastPathComponent()
                                .appendingPathComponent(file)
                                .absoluteString {
                            mutableDefaults = UserDefaults.defaultsForPlist(path: childPath, defaults: mutableDefaults)
                        }
                    }
                } else {
                    print("Error no PreferenceSpecifiers in \(path)")
                }
            } catch {
                print("Error reading plist: \(error) in \(path)")
            }
        } else {
            print("No plist found found at \(path)")
        }
        return mutableDefaults
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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