0

I have created a simple app in Swift that contains a WebViewControl. Thanks to a SettingsBundle the user is able to specify a URL that is then opened in the WebView. Root.plist looks like this:

<?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>PSTextFieldSpecifier</string>
            <key>Title</key>
            <string>URL</string>
            <key>Key</key>
            <string>app_url</string>
            <key>DefaultValue</key>
            <string>https://myurl.com</string>
            <key>IsSecure</key>
            <false/>
            <key>KeyboardType</key>
            <string>URL</string>
            <key>AutocapitalizationType</key>
            <string>None</string>
            <key>AutocorrectionType</key>
            <string>No</string>
        </dict>
    </array>
</dict>
</plist>

This works fine. However when trying to retrieve the app_url in Swift I am running in a problem.

override func viewDidLoad() {
    super.viewDidLoad()

    registerSettingsBundle()

    print("retrieving key")
    if let appUrl = UserDefaults.standard.string(forKey: "app_url") {
        print("got it " + appUrl)
    }
}

func registerSettingsBundle(){
    let appDefaults = [String:AnyObject]()
    UserDefaults.standard.register(defaults: appDefaults)
}

This prints retrieving key to the console, but never the second print statement.

It was working a while ago, but a recent update broke it. What am I doing wrong? Has the API changed somehow? I read the documentation from Apple on UserDefaults, but it hasn't helped me so far.

Edit regarding marked as duplicate: It is crucial that the user is able to change app_url using the Settings app in iOS. Just reading the plist file as a dict is not sufficient. Please excuse me, this is the first time I am experimenting with iOS apps.

dislick
  • 667
  • 1
  • 7
  • 25
  • How does the URL get to `UserDefaults` from your `.plist` file? – Dávid Pásztor Oct 10 '18 at 08:56
  • Root.plist != UserDefaults. To read from plist: https://stackoverflow.com/questions/24045570/how-do-i-get-a-plist-as-a-dictionary-in-swift – Larme Oct 10 '18 at 09:00
  • @DávidPásztor Please see my edit. – dislick Oct 10 '18 at 09:05
  • @dislick why are you registering the app defaults, as you can get the value from sharedDefaults of app bundle. – Harjot Singh Oct 10 '18 at 09:08
  • @vadian Thank you. I removed the `registerSettingsBundle` function completely, however I am still unable to retrieve the URL. Any other ideas? – dislick Oct 10 '18 at 09:16
  • I updated my answer, you could try first `object(forKey` to check if there is a value at all. – vadian Oct 10 '18 at 09:20
  • @vadian `if let appUrl = UserDefaults.standard.object(forKey: "app_url") { print("got it") }` does not print `got it` sadly. – dislick Oct 10 '18 at 09:23
  • Does the value appear in the settings of the app on the device? If yes you should be able to read it via `UserDefaults`, too. – vadian Oct 10 '18 at 09:25
  • @vadian Yes it appears in the settings app on the device. I can even change the value in the plist, re build the app and the new value appears in the settings app. – dislick Oct 10 '18 at 09:47

2 Answers2

0

I reopened the question because it's not a duplicate. The settings plist should not opened in code anyway.

The problem is registerSettingsBundle. After calling this method the defaults dictionary is empty and retrieving any data will fail. Don't call registerSettingsBundle as you declared the default value in the settings bundle.

registerSettingsBundle()

And as the type is URL use url(forKey

vadian
  • 274,689
  • 30
  • 353
  • 361
-1

You are trying to get data from plist so you need to do like this

if let path = Bundle.main.path(forResource: "SettingsBundle", ofType: "plist") {

    //plist contain root as Array
    if let arrayData = NSArray(contentsOfFile: path) as? [[String: Any]] {

    }

    //Or plist contain root as Dictionary
    if let dictData = NSDictionary(contentsOfFile: path) as? [String: Any] {

    }
}

If you want to change the plist data then use this:

var dictionaryPath = NSBundle.mainBundle().pathForResource("SettingsBundle", ofType: "plist")

var dictionary = NSMutableDictionary(contentsOfFile: dictionaryPath!)

var array = dictionary?.objectForKey("key")? as NSMutableArray

//this is a label I have called player1Name
array[0] = ""

playersDictionary?.writeToFile(dictionaryPath!, atomically: true)
Jogendar Choudhary
  • 3,476
  • 1
  • 12
  • 26