Search code examples
xcodemacosnsuserdefaults

macOS command line app - User Defaults dictionaryRepresentation shows too many values


I a developing a macOS commandline application in Xcode, which uses User Defaults. I have the following code for my User Defaults

if let configDefaults = UserDefaults.init(suiteName: "com.tests.configuration") {
    configDefaults.set("myStringValue", forKey: "stringKey")
    configDefaults.synchronize()
    print(configDefaults.dictionaryRepresentation())
}

This will create my own .plist file in the ~/Library/Preferences folder. If I look into the file, I can see only my single value which I added, which is perfectly fine. But when I call dictionaryRepresentation() on my UserDefaults object, the there are a lot of other attributes (I guess from the shared UserDefaults object), like

com.apple.trackpad.twoFingerFromRightEdgeSwipeGesture or AKLastEmailListRequestDateKey

Looking into the documentation of UserDefaults, it seems that this has to do with the search list of UserDefaults and that the standard object is in the search list:

func dictionaryRepresentation() -> [String : Any]

Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.

There are also the methods addSuite and removeSuite for a UserDefaults object, so I am guessing I need to remove the .standard suite from my configDefaults object, but I don't know the name, which should be used for that in the method.

Is it possible to remove the .standard defaults from the dictionary representation? I basically just want all of my own data in a dictionary, nothing more.

The reason I am trying to get only my values from the UserDefaults, is that a have a number of object of a custom type Connection (which store the configuration to connect to a server), which are saved in the UserDefaults. On program start I want to be able to load all objects into my app. Therefore I thought I could use dictionaryRepresentation(), as it would return all elements in the UserDefaults. But then there should be only my Connection objects in the dictionary, so that I can cast it to [String: Connection].


Solution

  • Given your purpose (in your latest edit of your question), what you should do is store a collection of Connection objects under a single key. Then, look up that key to get the collection.

    It's not clear if the collection should be an array of Connection objects or a dictionary mapping strings to Connections. That's a choice you can make.

    But, in any case, you shouldn't rely on the defaults being empty of everything else.

    In other words, you would do:

    UserDefaults.standard.set(yourStringToConnectionDictionary, forKey:"yourSingleKey")
    

    and later:

    let connectionMap = UserDefaults.dictionary(forKey:"yourSingleKey")
    

    then look up Connections in the connectionMap by their name/ID/whatever.