如何从 Objective-c/Swift 中的 settings.bundle 中检索值?

发布于 2024-11-15 01:03:45 字数 328 浏览 4 评论 0原文

我创建了一个项目,用于设置和检索settings.bundle 中的值。我还在 settings.bundle 文件中设置了一些默认值。现在的问题是,当我

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
loginName.text = [defaults objectForKey:@"login_name"];

第一次检索值时,它显示为 null,但这些值是在 iPhone 应用程序设置中设置的。 如果我更改值或手动设置它,则可以正确检索值。

帮帮我

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 is when I retrieve values as

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
loginName.text = [defaults objectForKey:@"login_name"];

for the first time it shows null, but the values get set in iPhone application settings.
If I change the values or set it manually, then values are retrieved properly.

Help me out

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

零時差 2024-11-22 01:03:45

尽管您定义了默认设置,但它们并未真正存储为值。它们被存储为默认值。如果您尝试读取它,则该值为空。默认设置是另一个属性,就像值一样。但这并不意味着将默认值写入为默认值。

我所做的是,首先,检查某些设置(我确信应该有一个值)是否存储了任何内容。如果它没有任何内容,那么我会编写所有默认值。

这是一个例子。

在 AppDelegate.m 上,我检查 email_notificaciones_preference 是否有值,如果没有,我将所有默认设置写入每个设置。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
    NSString * email_notificaciones_preference = [standardUserDefaults objectForKey:@"email_notificaciones_preference"];
    if (!email_notificaciones_preference) {
        [self registerDefaultsFromSettingsBundle];
    }

}

我用这个函数为每个元素写入默认值。

#pragma NSUserDefaults
- (void)registerDefaultsFromSettingsBundle {
    // this function writes default settings as settings
    NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
    if(!settingsBundle) {
        NSLog(@"Could not find Settings.bundle");
        return;
    }

    NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
    NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];

    NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
    for(NSDictionary *prefSpecification in preferences) {
        NSString *key = [prefSpecification objectForKey:@"Key"];
        if(key) {
            [defaultsToRegister setObject:[prefSpecification objectForKey:@"DefaultValue"] forKey:key];
            NSLog(@"writing as default %@ to the key %@",[prefSpecification objectForKey:@"DefaultValue"],key);
        }
    }

    [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];

}

希望有帮助。

Although you define the defaults settings, they are not really stored as a value. They are stored as default. If you try to read it, the value is null. Default setting is another property as value is. But it doesnt mean that will write the default value as a default.

What I do is, first, check if some setting,(that I'm sure that should have a value) has anything stored on it. If it doesn't have anything then I write all the defaults.

Here is an example.

on AppDelegate.m I check if email_notificaciones_preference has a value, if not, I write ALL default settings to each setting.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
    NSString * email_notificaciones_preference = [standardUserDefaults objectForKey:@"email_notificaciones_preference"];
    if (!email_notificaciones_preference) {
        [self registerDefaultsFromSettingsBundle];
    }

}

This function is what I use to write defaults to each element.

#pragma NSUserDefaults
- (void)registerDefaultsFromSettingsBundle {
    // this function writes default settings as settings
    NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
    if(!settingsBundle) {
        NSLog(@"Could not find Settings.bundle");
        return;
    }

    NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
    NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];

    NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
    for(NSDictionary *prefSpecification in preferences) {
        NSString *key = [prefSpecification objectForKey:@"Key"];
        if(key) {
            [defaultsToRegister setObject:[prefSpecification objectForKey:@"DefaultValue"] forKey:key];
            NSLog(@"writing as default %@ to the key %@",[prefSpecification objectForKey:@"DefaultValue"],key);
        }
    }

    [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];

}

Hope that helps.

旧城烟雨 2024-11-22 01:03:45

如果有人需要它 - 我将答案从 MIQUEL 翻译为 Swift(尽我所能,因为我仍在学习):

var standardUserDefaults = NSUserDefaults.standardUserDefaults()
var us: AnyObject? = standardUserDefaults.objectForKey("your_preference")
if us==nil {
    self.registerDefaultsFromSettingsBundle();
}

以及 func registerDefaultsFromSettingsBundle:

func registerDefaultsFromSettingsBundle() {
    // this function writes default settings as settings
    var settingsBundle = NSBundle.mainBundle().pathForResource("Settings", ofType: "bundle")
    if settingsBundle == nil {
        NSLog("Could not find Settings.bundle");
        return
    }
    var settings = NSDictionary(contentsOfFile:settingsBundle!.stringByAppendingPathComponent("Root.plist"))!
    var preferences: [NSDictionary] = settings.objectForKey("PreferenceSpecifiers") as [NSDictionary];
    var defaultsToRegister = NSMutableDictionary(capacity:(preferences.count));

    for prefSpecification:NSDictionary in preferences {
        var key: NSCopying? = prefSpecification.objectForKey("Key") as NSCopying?
        if key != nil {
            defaultsToRegister.setObject(prefSpecification.objectForKey("DefaultValue")!, forKey: key!)
        }
    }
    NSUserDefaults.standardUserDefaults().registerDefaults(defaultsToRegister);  
}

If anyone needs it - I translated the answer from MIQUEL to Swift (as good as I could as I'm still learning) :

var standardUserDefaults = NSUserDefaults.standardUserDefaults()
var us: AnyObject? = standardUserDefaults.objectForKey("your_preference")
if us==nil {
    self.registerDefaultsFromSettingsBundle();
}

And the func registerDefaultsFromSettingsBundle:

func registerDefaultsFromSettingsBundle() {
    // this function writes default settings as settings
    var settingsBundle = NSBundle.mainBundle().pathForResource("Settings", ofType: "bundle")
    if settingsBundle == nil {
        NSLog("Could not find Settings.bundle");
        return
    }
    var settings = NSDictionary(contentsOfFile:settingsBundle!.stringByAppendingPathComponent("Root.plist"))!
    var preferences: [NSDictionary] = settings.objectForKey("PreferenceSpecifiers") as [NSDictionary];
    var defaultsToRegister = NSMutableDictionary(capacity:(preferences.count));

    for prefSpecification:NSDictionary in preferences {
        var key: NSCopying? = prefSpecification.objectForKey("Key") as NSCopying?
        if key != nil {
            defaultsToRegister.setObject(prefSpecification.objectForKey("DefaultValue")!, forKey: key!)
        }
    }
    NSUserDefaults.standardUserDefaults().registerDefaults(defaultsToRegister);  
}
迷雾森÷林ヴ 2024-11-22 01:03:45

更新为 Swift 3:

func registerDefaultsFromSettingsBundle() {

    let userDefaults = UserDefaults.standard

    if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"),
        let settings = NSDictionary(contentsOf: settingsURL),
        let preferences = settings["PreferenceSpecifiers"] as? [NSDictionary] {

        var defaultsToRegister = [String: AnyObject]()
        for prefSpecification in preferences {
            if let key = prefSpecification["Key"] as? String,
                let value = prefSpecification["DefaultValue"] {

                defaultsToRegister[key] = value as AnyObject
                debugPrint("registerDefaultsFromSettingsBundle: (\(key), \(value)) \(type(of: value))")
            }
        }

        userDefaults.register(defaults: defaultsToRegister)

    } else {
        debugPrint("registerDefaultsFromSettingsBundle: Could not find Settings.bundle")
    }
}

Updated for Swift 3:

func registerDefaultsFromSettingsBundle() {

    let userDefaults = UserDefaults.standard

    if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"),
        let settings = NSDictionary(contentsOf: settingsURL),
        let preferences = settings["PreferenceSpecifiers"] as? [NSDictionary] {

        var defaultsToRegister = [String: AnyObject]()
        for prefSpecification in preferences {
            if let key = prefSpecification["Key"] as? String,
                let value = prefSpecification["DefaultValue"] {

                defaultsToRegister[key] = value as AnyObject
                debugPrint("registerDefaultsFromSettingsBundle: (\(key), \(value)) \(type(of: value))")
            }
        }

        userDefaults.register(defaults: defaultsToRegister)

    } else {
        debugPrint("registerDefaultsFromSettingsBundle: Could not find Settings.bundle")
    }
}
寒江雪… 2024-11-22 01:03:45

swift 2.1 的更新版本:

 func registerDefaultsFromSettingsBundle() {
    let userDefaults = NSUserDefaults.standardUserDefaults()

    if let settingsURL = NSBundle.mainBundle().URLForResource("Root", withExtension: "plist", subdirectory: "Settings.bundle"),
           settings = NSDictionary(contentsOfURL: settingsURL),
           preferences = settings["PreferenceSpecifiers"] as? [NSDictionary] {

        var defaultsToRegister = [String: AnyObject]()
        for prefSpecification in preferences {
            if let key = prefSpecification["Key"] as? String,
                   value = prefSpecification["DefaultValue"] {

                defaultsToRegister[key] = value
                NSLog("registerDefaultsFromSettingsBundle: (\(key), \(value)) \(value.dynamicType)")
            }
        }

        userDefaults.registerDefaults(defaultsToRegister);
    } else {
        NSLog("registerDefaultsFromSettingsBundle: Could not find Settings.bundle");
    }
}

Updated version for swift 2.1:

 func registerDefaultsFromSettingsBundle() {
    let userDefaults = NSUserDefaults.standardUserDefaults()

    if let settingsURL = NSBundle.mainBundle().URLForResource("Root", withExtension: "plist", subdirectory: "Settings.bundle"),
           settings = NSDictionary(contentsOfURL: settingsURL),
           preferences = settings["PreferenceSpecifiers"] as? [NSDictionary] {

        var defaultsToRegister = [String: AnyObject]()
        for prefSpecification in preferences {
            if let key = prefSpecification["Key"] as? String,
                   value = prefSpecification["DefaultValue"] {

                defaultsToRegister[key] = value
                NSLog("registerDefaultsFromSettingsBundle: (\(key), \(value)) \(value.dynamicType)")
            }
        }

        userDefaults.registerDefaults(defaultsToRegister);
    } else {
        NSLog("registerDefaultsFromSettingsBundle: Could not find Settings.bundle");
    }
}
嗼ふ静 2024-11-22 01:03:45

您可以使用像这样的简单属性包装器:

用法

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

注意,只需在变量前添加 @objc 即可 100% 兼容 Objective-C。


其背后的代码实现:

设置捆绑包值位于 UserDefaults 中,因此您可以为其使用自定义 PropertyWrapper。以下包装器适用于任何 UserDefault 值,包括 SettingsBundle 的所有值。

属性包装器

@propertyWrapper
public struct SettingsBundleStorage<T> {    
    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) }
    }
}

根和子级

您应该为根和子级 plist 传递以下枚举:

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

如果需要,查找并设置默认值。

此包装器使用此函数查找捆绑包键的默认值:

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

此包装器可以将任何类型的可编码存储到用户默认值中或从用户默认值恢复,包括已经符合可编码的所有 Swift 标准数据类型。


此外,您还可以找到一个类似但代码更少的版本,用于从任何用户默认值访问任何键值,您可以查看这个答案在这里

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<T> {    
    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

死开点丶别碍眼 2024-11-22 01:03:45

试试这个

注册设置捆绑包的默认值

NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:defaultValue forKey:@"key"];
 [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];

在检索设置捆绑包值同步数据之前

[[NSUserDefaults standardUserDefaults] synchronize]

try this

To register Default Values of Setting bundles

NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:defaultValue forKey:@"key"];
 [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];

Before retrieving setting bundles values synchronize data

[[NSUserDefaults standardUserDefaults] synchronize]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文