How to print NSUserDefaults content in Swift - ios

How do you print all the content of NSUserDefaults?
I need to see everything that has been stored into NSUserDefaults. Is there a simple way to print that or to see it into the logs?
In Swift!
Thank you

Taken from - Retrieve UserDefaults in Swift
In Swift we can use the following:-
Swift 3.x & 4.x
For getting all keys & values:
for (key, value) in UserDefaults.standard.dictionaryRepresentation() {
print("\(key) = \(value) \n")
}
For retrieving the complete dictionary representation of user defaults:
print(Array(UserDefaults.standard.dictionaryRepresentation()))
For retrieving the keys:
// Using dump since the keys are an array of strings.
dump(Array(UserDefaults.standard.dictionaryRepresentation().keys))
For retrieving the values:
We can use dump here as well, but that will return the complete inheritance hierarchy of each element in the values array. If more information about the objects is required, then use dump, else go ahead with the normal print statement.
// dump(Array(UserDefaults.standard.dictionaryRepresentation().values))
print(Array(UserDefaults.standard.dictionaryRepresentation().values))
Swift 2.x
For retrieving the complete dictionary representation of user defaults:
print(NSUserDefaults.standardUserDefaults().dictionaryRepresentation())
For retrieving the keys:
print(NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys.array)
For retrieving the values:
print(NSUserDefaults.standardUserDefaults().dictionaryRepresentation().values.array)

for elem in NSUserDefaults.standardUserDefaults().dictionaryRepresentation() {
println(elem)
}

Here is the syntax in to get all standard user defaults in Swift 3
print(UserDefaults.standard().dictionaryRepresentation())

With Swift 3.0
print(UserDefaults.standard.dictionaryRepresentation())

Here is the syntax that provide more clarity.
let defaults = UserDefaults.standard
defaults.dictionaryRepresentation().map{print("\($0.key): \($0.value)")}

Related

Determining Swift Types That Can Be Stored in UserDefaults

I am in the beginning stages of developing an open-source utility for storing state in the Bundle UserDefaults.
I'm encountering an issue when I add non-Codable data types to my Dictionary of [String: Any].
I need to be able to vet the data before trying to submit it, because the UserDefaults.set(_:) method won't throw any errors. It just crashes.
So I want to make sure that the Dictionary that I'm submitting is kosher.
I can't just check if it's Codable, because it can sometimes say that it isn't, when the struct is actually good. (It's a Dictionary<String, Any>, and I can cram all kinds of things in there).
I need to validate that the Dictionary can produce a plist. If this were ObjC, I might use one of the NSPropertyListSerialization methods to test the Dictionary, but it appears as if this set of methods is not available to Swift.
According to the UserDefaults docs, there are a specific set of types and classes that are "plist-studly."
I think testing each type in the list is unacceptable. I need to see if I can find a way to test that won't be screwed the first time Apple updates an OS.
Is there a good way to test a Dictionary<String, Any> to see if it will make UserDefaults.set(_:) puke?
The Property List type set of UserDefaults is very limited. The supported types are
NSString → Swift String
NSNumber → Swift Int, Double or Bool
NSDate → Swift Date
NSData → Swift Data
Arrays and dictionaries containing the 4 value types.
Any is not supported unless it represents one of the 4 value or 2 collection types.
Property List compliant collection types can be written to UserDefaults with PropertyListSerialization (even in Swift).
There are two protocols to serialize custom types to Data
Codable can serialize structs and classes.
NSCoding can serialize subclasses of NSObject.
All types in the structs/classes must be encodable and decodable (means conform to the protocol themselves).
The APIs of PropertyListSerialization / PropertyListEncoder/-Decoder and NSKeyed(Un)Archiver provide robust error handling to avoid crashes.
UPDATE[1]: And, just because I like to share, here's the actual completed project (MIT License, as is most of my stuff)
UPDATE: This is the solution I came up with. Even though I greenchecked vadian's excellent answer, I decided to get a bit more picky.
Thanks to matt pointing out that I was looking under the wrong sofa cushions for the keys, I found the Swift variant of NSPropertyListSerialization, and I use that to vet the top level of the tree. I suspect that I'll need to refactor it into a recursive crawler before I'm done, but this works for now.
Here's the code for the _save() method at the time of this writing. It works:
/* ################################################################## */
/**
This is a private method that saves the current contents of the _values Dictionary to persistent storage, keyed by the value of the "key" property.
- throws: An error, if the values are not all codable.
*/
private func _save() throws {
#if DEBUG
print("Saving Prefs: \(String(describing: _values))")
#endif
// What we do here, is "scrub" the values of anything that was added against what is expected.
var temporaryDict: [String: Any] = [:]
keys.forEach {
temporaryDict[$0] = _values[$0]
}
_values = temporaryDict
if PropertyListSerialization.propertyList(_values, isValidFor: .xml) {
UserDefaults.standard.set(_values, forKey: key)
} else {
#if DEBUG
print("Attempt to set non-codable values!")
#endif
// What we do here, is look through our values list, and record the keys of the elements that are not considered Codable. We return those in the error that we throw.
var valueElementList: [String] = []
_values.forEach {
if PropertyListSerialization.propertyList($0.value, isValidFor: .xml) {
#if DEBUG
print("\($0.key) is OK")
#endif
} else {
#if DEBUG
print("\($0.key) is not Codable")
#endif
valueElementList.append($0.key)
}
}
throw PrefsError.valuesNotCodable(invalidElements: valueElementList)
}
}

iOS Firebase : Add data to firebase node of array type

I got node in the firebase named "XXXXX".
I want to add tokenids to this node.
But in iOS I am having problem updating tokensids.
Do we got functions in iOS for appending data to iOS Firebase?
or we have to first get the token from firebase , append our token and save the token array back to node ?
Any suggestion guys ?
No, you cannot append data to an array in Firebase using any Firebase query.
But, there is a way by using dictionary as arrayObjectToAdd: true,
self.ref.child("ArrayMainNode").setValue(["arrayObjectToAdd": "true"])
To remove an array object, you can directly use
self.ref.child("ArrayMainNode").child("arrayObjectToAdd").removeValue()
You can do it this way:
let ref = FIRDatabase.database().reference(withPath: "somePath/array").child(newArrayObjectKey)
ref.setValue("true") // or whatever
Hope it helps
You can do it by this way:
let refInsert = Database.database().reference()
self.refInsert.updateChildValues(["Your node": "\(new token)"])

Kinvey 3.3.5 SDK Query By Ids

I am currently going through the processes of migrating swift 2.3 to 3 using the most updated Kinvey SDK (version 3.3.5). They have done a ton of updates since the 1x versions. My question is has anyone successfully been able to query on the PersistableKeyID field and pull multiple objects?
I use to be able to use the "loadObjects" function which would take an array of strings as an argument. This function has since been depreciated and replaced with find(byId). See below:
dataStore.find(byId: "only takes one") { uClass, error in
if let uClass = uClass {
//succeed
print("UClass: \(uClass)")
} else {
//fail
}
The issue is, it will only take a single string as an argument. I have attempted to use the query functionality, but I cannot get it to take the "_id" field as a parameter. Using the following code:
//Just statically creating the sectionID array for now. This will dynamically be created
testIDs = ["58668307206c11177e5ab0d4", "58668307206c11177e5ab0d4", "57ad00a505a2bb55632659c3"]
let sectionStore = DataStore<Section>.collection()
let sectionQuery = Query(format: "_id IN %#", testIDs)
sectionStore.find(sectionQuery) {sectionResult, error in
if let sectionResult = sectionResult {
self.sectionsTest = sectionResult
self.sectionCollectionView.reloadData()
} else{
//Error
}
}
I receive the error:
'Invalid property name', reason: 'Property '_id' not found in object of type 'Section'
Anyone have an idea on how to perform this now that "loadObjects" has been depreciated? There is no delivered "find(byIds)" that I could find.
Jbone107,
I was able to get results with this, let me know if the below works for you.
let id:[String] = ["5855026650a816ec29012908","5855024a21400c5b492bea20"]
let query = Query(format: "_id IN %#", id)
dataStore.find(query) { data, error in
if let data = data {
//succeed
print(“Data: \(data)")
} else {
//fail
print("fetching failed")
}
}
Thanks,
Pranav,
Kinvey
Answered: Per the Data Store Guide for iOS, by default the ".collection()" is of type "cache". The "Cache" type will store data locally. This must be why "Realm" is now included with the version 3x SDK.
I updated my DataStore collection to:
let sectionStore = DataStore<Section>.collection(.network)
I added ".network" to force the query to pull from the backend rather than the cache file. This actually identified "_id" as a property and the query worked successfully. For some reason the "cache" file isn't storing this as a property.
Additional SDK Question Answered
I was having an issue pulling NSNumber from the Kinvey backend. This ended up being a similar issue related to the "cache" query. I reviewed the Realm support site as a last resort effort to try and figure this out. I found that Realm doesn't actually support type "NSNumber".
Excerpt taken from: https://realm.io/docs/swift/latest/
Realm supports the following property types: Bool, Int8, Int16, Int32, Int64, Double, Float, String, NSDate, and NSData.
Unfortunately, Kinvey doesn't support "Int" types. As a work around, I have changed them to string and am just converting back to "Double" or another type after I pull the data. However, if I just use ".network" collection types, then NSNumber still works.
Thanks,
James

Swift 3 Migration Cleared NSUserDefault Data

I'm not sure how to use the new UserDefaults class with the new Swift3 changes.
I had this code prior to the migration to swift3 which successfully retrieved the data stored in the userDefaults:
if NSUserDefaults.standardUserDefaults().objectForKey("profileArray") != nil {
profileArray = NSUserDefaults.standardUserDefaults().objectForKey("profileArray") as! [String]
}
With the migration to swift3 the code is now:
if UserDefaults.standard.object(forKey: "profileArray") != nil {
profileArray = UserDefaults.standard.object(forKey: "profileArray")! as! [NSString]
}
The new syntax makes sense but when I run the project the data that was previously stored in the user default seems to be gone.The userdefault.standard... is now returning empty/nil.
How do I retrieve the data that was stored prior to the swift3 migration?
Appreciate the help with moving to swift3!
I don't know if that solves your problem, but your syntax is not very efficient – you retrieve the object from user defaults unnecessarily twice.
The recommended way is optional binding and the dedicated method to get an array:
if let array = UserDefaults.standard.array(forKey: "profileArray") as? [String] {
profileArray = array
}
Im Swift use always String rather than NSString unless you have no choice.
I have finally figured this out. The userDefaults weren't "cleared". but the userDefaults are specific to a device. so with the migration to xcode8 the iOS simulators were also upgraded....and these are technically new devices where userDefaults had never been captured.
I proved this theory by adding a simulator (you can go back and re-install iOS 9.x simulators) and this worked.
I also tested on a real device using iOS 9.x & the new swift 3 code and the defaults persisted on that device.
So problem solved! :)

Building a dictionary at runtime in Swift 2.0

I am trying to build a simple dictionary at runtime in Swift. I am fairly new to Swift, but experienced in Obj-C (and missing it).
I am gathering some JSON data via a web service and looping through its elements. During this loop I need to build the dictionary. Here is the dictionary I need to generate
"gauge": {
"gaugeID" : "03185"
"name" : "SOME GAUGE NAME"
"cfs" : 8410
"stage" : 7.05
}
Since values for cfs and flow may not be present, I need to add these values to the dictionary conditionally.
I have declared the following dictionary
var dictEntry:[String:AnyObject]
Then as I loop through the dictionary I need to build each key-value and add it to the dictEntry dictionary. Every attempt I've made to do this fails. In Obj-C I could do the following:
[entryDict setValue:someValue forKey:#"cfs"];
How is this possible in Swift? Thanks!
Here you go:
dictEntry["cfs"] = someValue

Resources