2016-03-27 87 views
5

我添加了一个设置包到我的应用程序,并在Xcode它出现在我的项目树视图的根。设置包值返回零

Root.plist文件看起来是这样的:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
    <key>StringsTable</key> 
    <string>Root</string> 
    <key>PreferenceSpecifiers</key> 
    <array> 
     <dict> 
      <key>Type</key> 
      <string>PSGroupSpecifier</string> 
      <key>Title</key> 
      <string>Service</string> 
     </dict> 
     <dict> 
      <key>Type</key> 
      <string>PSTextFieldSpecifier</string> 
      <key>Title</key> 
      <string>Hostname</string> 
      <key>Key</key> 
      <string>service_hostname</string> 
    <!-- and so on --> 

当我打开设置应用程序在iOS上的条目出现在底部,我可以显示和编辑我的设置完全正常。

但是我无法从代码中检索这些值。这里是我的代码:

static func loadSettings() { 

    let ud = NSUserDefaults.standardUserDefaults() 
    ud.synchronize() 

    Settings.hostName = ud.stringForKey("service_hostname") 
    // etc 
} 

我也试过ud.objectForKeyud.valueForKey - 都返回nil为好。

设置Settings.hostName之后,Xcode调试器报告它的值为nil,尽管我在Settings应用程序中设置了显式值。

我看到这个线程(iPhone App : How to get default value from root.plist?),其中有人张贴的Objective-C代码块是直接手动加载Root.plist文件为NSMutableDictionary,并调用NSUserDefaults.standardUserDefaults().registerDefaults,但似乎像一个黑客攻击(我不能让它开始工作在Swift中,因为编译器说stringByAppendingPathComponent不存在了)

为什么NSUserDefaults从Settings应用程序中获取设置?

回答

7

显然的原因是,如果我在plist设置定义了默认值,用户没有明确设置的值,然后在设置中显示的值应用将从plist文件的默认值,但是NSUserDefaults API会仍然返回nil

不幸的是,这意味着如果默认值是有意义的(如默认Web服务地址URI:“http://www.example.com”),则必须在我的项目有两次:如plist,在我的程序代码的默认:

Root.plist:

​​

Program.swift:

let ud = NSUserDefaults.standardUserDefaults() 
ud.synchronize() 

var mySettingValue = ud.stringForKey("mySettingKey") 
if mySettingValue == nil { 
    mySettingValue = "http://www.example.com" 
} 

这是令人惊讶的。

+0

我觉得我疯了。搜索一个很长一段时间的解决方案!这是为什么发生?有谁知道? –

+0

@戴这不适合我,它给零价值..我错过了什么? – mm24

+0

@ mm24“它给出了一个零值” - 这就是我发布的内容,为什么解决方案是检查零值并在代码中提供默认值。 – Dai

7

您应该注册您的默认值,以便它将同步。 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") 

请记住,你也应该使用registerDefaults:当你的应用程序使用一个Settings程序包。由于您已经在设置包的plist中指定了默认值,因此您可能会希望您的应用程序自动选取这些值。但是,情况并非如此。包含在设置包中的信息只能通过iOS Settings.app读取,而不能通过您的应用程序读取。为了使您的应用程序使用Settings.app中显示的相同默认值,您必须手动将用户默认值和默认值复制到单独的plist文件中,并将其注册到默认值数据库中,如上所示。

+0

有趣的是,当我注册并同步了我的值,然后立即转过身来查询它们的值,我什么也得不到......不得不做旧式的“setObject:forKey:”。 – BonanzaDriver

+0

调用'synchronize'在这里毫无意义。 1.调用'register'并不会改变任何东西,所以没有什么可以同步。 2.调用'同步'永远不需要任何方式。 – rmaddy

7

默认值可以从Settings.bundle中获取并添加到UserDefaults。以下功能可从didFinishLaunchingWithOptions调用AppDelegate.swift

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

这里有一个更好的用法。一旦你得到'preferences',就用'UserDefaults寄存器'来使用它。它比循环和明确设置每个值要好得多。 – rmaddy

+0

@rmaddy在这里,我检查UserDefaults是否已经包含特定的键,并且我没有在这种情况下设置。不确定UserDefaults.register(:)如何在这种情况下工作 –