How to retrieve values from settings.bundle in Objective-c/Swift?

后端 未结 6 513
独厮守ぢ
独厮守ぢ 2020-12-08 07:52

I have created a project that set and retrieve values from settings.bundle. I have also set some defaults values in settings.bundle file. Now the problem i

6条回答
  •  囚心锁ツ
    2020-12-08 08:34

    You can use a simple property wrapper like this:

    Usage

    @SettingsBundleStorage(key: "storageUsage_preference")
    var storageUsage: Double
    

    Note that this is 100% objective-c compatible by just adding @objc before the variable.


    Implementation of the code behind this:

    Settings bundle values are live in the UserDefaults so you can use a custom PropertyWrapper for it. The following wrapper will work for any UserDefault value, including all values of the SettingsBundle.

    Property wrapper

    @propertyWrapper
    public struct SettingsBundleStorage {    
        private let key: String
    
        public init(key: String) {
            self.key = key
            setBundleDefaults(plist: .root) // This is the main plist
            setBundleDefaults(plist: .child(name: "DeveloperOptions")) // This is an example child.
        }
    
        public var wrappedValue: T {
            get { UserDefaults.standard.value(forKey: key) as! T }
            set { UserDefaults.standard.set(newValue, forKey: key) }
        }
    }
    

    The root and the children

    You should pass the following enum for the root and the child plists:

    extension SettingsBundleStorage {
    
        enum PList {
            case root
            case child(name: String)
    
            var name: String {
                var file: String
                switch self {
                case .root: file = "Root"
                case .child(let name): file = name.replacingOccurrences(of: ".plist", with: "")
                }
                file.append(".plist")
                return file
            }
        }
    }
    

    Find and set defaults if needed.

    This wrapper finds the default value of the bundle keys with this function:

    extension SettingsBundleStorage {
    
        func setBundleDefaults(plist: PList = .root) {
            let settingsName                    = "Settings"
            let settingsExtension               = "bundle"
            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(plist.name)),
                  let settingsPlist = try? PropertyListSerialization.propertyList(
                    from: settingsData,
                    options: [],
                    format: nil) as? [String: Any],
                  let settingsPreferences = settingsPlist?[settingsPreferencesItems] as? [[String: Any]] else {
                return assertionFailure("Can not get the \(plist.name) from the bundle: \(settingsName)")
            }
    
            var defaultsToRegister = [String: Any]()
    
            settingsPreferences.forEach { preference in
                if let key = preference[settingsPreferenceKey] as? String {
                    defaultsToRegister[key] = preference[settingsPreferenceDefaultValue]
                }
            }
    
            UserDefaults.standard.register(defaults: defaultsToRegister)
        }
    }
    

    This wrapper can store/restore any kind of codable into/from the user defaults including all Swift standard data types that are already conformed to the codable.


    Also, you can find a similar but with way less code version for accessing any key-value from any user default, you can take a look at this answer here

提交回复
热议问题