2016-03-27 104 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(:)如何在這種情況下工作 –