【问题标题】:How to retrieve values from settings.bundle in Objective-c/Swift?如何从 Objective-c/Swift 中的 settings.bundle 中检索值?
【发布时间】:2011-09-11 14:22:21
【问题描述】:

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

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

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

帮帮我

【问题讨论】:

    标签: objective-c swift iphone nsuserdefaults application-settings


    【解决方案1】:

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

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

    这是一个例子。

    在 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];
    
    }
    

    希望对您有所帮助。

    【讨论】:

    • 感谢您节省大量时间!
    • 非常好的解决方案 - 我将它翻译成 Swift 并在有人需要时将其添加为答案。
    • 是否也应该添加[[NSUserDefaults standardUserDefaults] synchronize];
    • 我使用 [[NSUserDefaults standardUserDefaults] 同步] 在检索数据之前而不是之后。
    【解决方案2】:

    如果有人需要 - 我将答案从 MIQUEL 翻译成 Swift(尽我所能):

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

    还有函数 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);  
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • Swift 3 有什么用吗?
        【解决方案5】:

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

        用法

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

        根和孩子

        您应该为根和子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
                }
            }
        }
        

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

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

        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 标准数据类型。


        此外,您可以找到一个类似但代码更少的版本,用于从任何用户默认访问任何键值,您可以查看this answer here

        【讨论】:

        • 这真是一个绝妙的答案!这应该是从现在开始使用属性包装器的方式
        【解决方案6】:

        试试这个

        注册设置包的默认值

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

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

        [[NSUserDefaults standardUserDefaults] synchronize]
        

        【讨论】:

          猜你喜欢
          • 2019-04-15
          • 2011-10-31
          • 1970-01-01
          • 2019-02-14
          • 2019-08-09
          • 2022-11-25
          • 2021-12-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多