How can I change this line in order to eliminate for loop? - swift

I have the below line. anyPosts is of type (key: String, value: AnyObject). This line however will only loop 1 time. So I would like to change it so that I can access anyposts.key withough using for loop.
Preferably I would like to only use 1 line. Like:
let anyPostKey = anyPosts as! [something...]
I have tried to find what to cast it to but I could not find anything.
for anyPosts in postDictionary {
Incase the info is relevant, postDict is of type: [String : AnyObject].

You have postDictionary which you claim to have one key/value pair.
Your goal is to access that one key.
let anyPostKey = postDictionary.keys.first! // will crash if dictionary is empty
anyPostKey will be a String since postDictionary is defined as [String: AnyObject].

Related

Swift: Dictionary of Dicitionaries, cannot get subscript

I've looked at other subscript issues here and I don't think they match my problem. I have a dictionary of dictionaries - Dictionary[String:Dictionary[String:String]]
In an extension I want to loop through all the values (Dictionary[String:String] and retrieve one of the values.
So I wrote this:
for dictNEO in Array(self.values) {
print(dictNEO)
print(type(of: dictNEO))
print(dictNEO["approachDate"])
}
and am getting this error on the last print line: Value of type 'Value' has no subscripts
Here's the first two print lines:
["nominalDist": "\"13.58 ", "approachDate": "\"2020-Feb-01 08:18 ± < 00:01\"", "minimumDist": "\"13.58 ", "diameter": "\"92 m - 210 m\"", "name": "\"(2017 AE5)\""]
Dictionary<String, String>
So I am confused as to why it is telling me it has no subscripts when it sees the type of as a Dictionary.
You have written this as an extension to Dictionary if I understand you correctly and that means that self is generic and defined as Dictionary<Key, Value> and not to you specific type so in your for loop you are looping over an array of [Value].
So you need to typecast Value before accessing it as a dictionary
if let dictionary = dictNEO as? [String: String] {
print(dictNEO["approachDate"])
}
but since it makes little sense to have an extension to Dictionary where you access a specific key it would be better to write it as a function. Since the dictionary is well defined now there is no issue with the last print
func printValuesForSubKey(_ key: String, _ dict: [String: [String: String]]) {
for (dictNEO) in dict.values {
print(dictNEO)
print(type(of: dictNEO))
print(dictNEO[key])
}
}
Note, I don't have an explanation why type(of:) recognises it as [String: String]
The code snippet doesn't work because values property is a collection of collections and with Array(values) you create a collection of collection of collections. In short, instead going down the code goes up and creates new collection level.
Solution with a Higher order function map:
self.values.map { print(type(of: $0)); $0["approachDate"] }
Solution with For-In Loop
for dictNEO in self.values {
print(dictNEO)
print(type(of: dictNEO))
print(dictNEO["approachDate"])
}

What is the difference between initializing a dictionary and declaring in Swift?

Not sure if my title is accurate. Please comment if so will update.
In one method I just create the dictionary and initialize it with ()
In the other I create it and immediately fill it with a key value pair.
What is the difference? Is one prefered over the other?
//initializing dictionary
var airPortCodesInitialize = [Int: String]()
//vs declaring
var airPortCodes: [String: String] = ["SLC": "Salt Lake City", "LAX": "Los Angeles"]
In both cases, you are declaring a dictionary and initializing it. The only difference is that the first line creates an empty dictionary, the second line creates a dictionary filled with key value pairs.
A single declaration looks like this:
var myDictionary: [String: String]
I think you misunderstood what declarations are, so for the rest of this answer, I will compare the line above and your first line.
What is the difference?
A single declaration gives the variable no value, so if you try to use myDictionary immediately after the declaration without initializing it, the compiler gives you an error:
print(myDictionary["Hello"]) // error
Is one prefered over the other?
Most of the time, you should put the initialisation and declaration on the same line like you did in
var airPortCodesInitialize = [Int: String]()
This is more readable.
Sometimes though, you might want different initial values for a constant dictionary depending on a value. Then you must separate the declaration and initialisation:
let myConstantDict: [String: String]
switch something {
case .foo:
myConstantDict = ...
case .bar:
myConstantDict = ...
}

Converting error: Type 'Any' has no subscript members

After converting the for loop to Swift 3 I got the error "Type 'Any' has no subscript members"
for inputKey in inputKeys where attributes[inputKey]?[kCIAttributeClass] == "NSNumber"
.....................^
{
}
I would expect to add something like
for inputKey in inputKeys where attributes[inputKey]as?[String:Any][kCIAttributeClass] == "NSNumber"
but this doesn't work :-(
Still have some problems with the Swift syntax.
It looks like you want attributes to actually be [String: [String: String]] - a dictionary of dictionaries.
Either that, or you can cast attributes[inputKey] to [String:String].
I think this would work:
for inputKey in inputKeys where (attributes[inputKey] as? [String:String])?[kCIAttributeClass] == "NSNumber"
Edit per comments:
Since attributes isn't actually guaranteed to be [String: [String: String]], but only [String: [String: Any]] (and maybe not even that), you'll need an extra as? cast to be safe.
With that many casts on one line, I think it would be better to put the test into a guard statement at the beginning of the for body instead of having such a huge where clause.

type 'Any' has no subscript members

let employerName = snapshot.value! ["employerName"] as! String
let employerImage = snapshot.value! ["employerImage"] as! String
let uid = snapshot.value! ["uid"] as! String
I reviewed previous posts but cannot seem to find a way to solve this problem. All three lines of code give the "type 'Any' has no subscript members" error. Fairly new to this so any help is appreciated.
snapshot.value has a type of Any. A subscript is a special kind of function that uses the syntax of enclosing a value in braces. This subscript function is implemented by Dictionary.
So what is happening here is that YOU as the developer know that snapshot.value is a Dictionary, but the compiler doesn't. It won't let you call the subscript function because you are trying to call it on a value of type Any and Any does not implement subscript. In order to do this, you have to tell the compiler that your snapshot.value is actually a Dictionary. Further more Dictionary lets you use the subscript function with values of whatever type the Dictionary's keys are. So you need to tell it you have a Dictionary with keys as String(AKA [String: Any]). Going even further than that, in your case, you seem to know that all of the values in your Dictionary are String as well, so instead of casting each value after you subscript it to String using as! String, if you just tell it that your Dictionary has keys and values that are both String types (AKA [String: String]), then you will be able to subscript to access the values and the compiler will know the values are String also!
guard let snapshotDict = snapshot.value as? [String: String] else {
// Do something to handle the error
// if your snapshot.value isn't the type you thought it was going to be.
}
let employerName = snapshotDict["employerName"]
let employerImage = snapshotDict["employerImage"]
let uid = snapshotDict["fid"]
And there you have it!
Since you want to treat snapshot.value as an unwrapped dictionary, try casting to one and, if it succeeds, use that dictionary.
Consider something like:
func findElements(candidate: Any) {
if let dict: [String : String] = candidate as? Dictionary {
print(dict["employerName"])
print(dict["employerImage"])
print(dict["uid"])
}
}
// Fake call
let snapshotValue = ["employerName" : "name", "employerImage" : "image", "uid" : "345"]
findElements(snapshotValue)

Can't assign String to AnyObject?

Ok, this is a weird one. I'm looping through an array of what apparently is a Dictionary<String, AnyObject?!> (notice the ?!, it's not a typo). I'm trying to assign a String to one of its keys, but it's not working and I get the weird error below.
Has anyone seen anything like this?
Edit:
Some extra info: even the debugger says it's an AnyObject?!:
You cannot apply the Dictionary syntax on an Array.
Try this:
if var dict = fields as? [String: String]{
dict["test"] = "test"
}