Codey
Codey

Reputation: 1233

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].

Upvotes: 1

Views: 573

Answers (2)

Codey
Codey

Reputation: 1233

Though the other solution proposed by Ken Thomases may be better from a design standpoint, I've found a solution that does exactly what I initially wanted. Calling

UserDefaults.standard.persistentDomain(forName: "com.company.TestApp.configuration")

Returns a dictionary containing only the values I've added to the domain com.company.TestApp.configuration, using

let configs = UserDefaults.init(suiteName: "com.company.TestApp.configuration")!
configs.set(someData, forKey: someKey)

Strangely in the Apple documentation says this about persistentDomain(forName:):

Calling this method is equivalent to initializing a user defaults object with init(suiteName:) passing domainName and calling the dictionaryRepresentation() method on it.

But this is not the case (see my question). Clarification on that subject is more than welcome.

Upvotes: 1

Ken Thomases
Ken Thomases

Reputation: 90641

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.

Upvotes: 2

Related Questions