Swift: Getting dictionary value if I know the key - swift

This should be super basic but I'm getting an error anyway.
Cannot subscript a value of type 'Dictionary<String, AnyObject>' with an index of type 'String'
Here's my code:
func createComments(attributes: [[String: AnyObject]], votes: [String: AnyObject], sid: Int) -> [Comment] {
var comments: [Comment] = [Comment]()
for commentAttributes in attributes {
let comment = Comment()
comment.commentId = commentAttributes["id"]
comments.append(comment)
}
return comments
}
I'm getting the error on this line:
comment.commentId = commentAttributes["id"]
As far as I can tell, commentAttributes should be a Dictionary with keys as Strings and values of AnyObject. I'm not sure how else to access the values of a Dictionary with a String key other than by using a String to subscript. What am I missing here?

Try to use if let and cast it to proper type.
for commentAttributes in attributes {
let comment = Comment()
if let id = commentAttributes["id"] as? Int {
comment.commentId = id
}
comments.append(comment)
}

Of course as soon as I ask the question I find the answer:
Cannot subscript a value of type '[String : AnyObject]' with an index of type 'String'
I needed to typecast the value of commentAttributes["id"] so that it matched the type of comment.commentId
comment.commentId = commentAttributes["id"] as! Int

Related

Swift 5.1: How do I call map on a collection of one type and return another of a different type?

I've been playing about with functional programming in Swift. However, I've encountered a problem.
If I call map on a collection of one type, how do I create a new collection of another type?
var fontFamilyMembers = [[Any]]()
//...
let postscriptNames = fontFamilyMembers.map {
[
"name": $0[0] as! String,
"weight": $0[2] as! Int,
"traits": $0[3] as! UInt
]
}
// Error: Value of type 'Any?' has no member 'count'
lengths = postscriptNames.map { $0["name"].count }
I understand I need to cast $0["name"] as a string. Why do I have to do that when I have already done it above? ("name": $0[0] as! String). Is that because postscriptNames is also type [[Any]]()?
I've tried this:
// Error: Cannot convert value of type 'Int' to closure result type 'String'
fontPostscriptNames = postscriptNames.map { ($0["name"] as! String).count }.joined(separator: "\n")
…but know I'm doubly confused.
How do I get map to return the count of each "name"?
Update
My original question still stands. However, I can avoid the problem altogether by using a struct as opposed to a dictionary which I assume is preferred in Swift.
let postscriptNames = fontFamilyMembers.map {
(
name: $0[0] as! String,
weight: $0[2] as! Int,
traits: $0[3] as! UInt
)
}
lengths = postscriptNames.map { $0.name.count }
Is that because postscriptNames is also type [Any]?
Yes. And as postscriptNames is of type [Any], you need to downcast $0.name to String
lengths = postscriptNames.compactMap { ($0.name as? String).count }
Downcast it to String to get the count.

Cannot subscript a value of type '[AnyObject]' with an index of type 'AnyObject'

I'm working in Swift 3.0 and I got a problem with my array.
Each line contains a dictionnary with 2 values.
When I want to change this value I have this message:
" Cannot subscript a value of type '[AnyObject]' with an index of type 'AnyObject' "
So,
I create "rows"
var rows: [AnyObject] = ["" as AnyObject]
Then I assign a value to rows[0] for have something in my TableView at the start.
let firstLine: [String : Any] = ["time": time, "Playing": false]
rows[0] = firstLine as AnyObject
And my problem is here. When I try to change the values in "rows".
var i: Int = 0
for i in rows {
rows[i]["playing"] = true
rows[i]["time] = time
}
Have a good day guys !
Don't declare your array as [AnyObject] because you clearly want to store a concrete type - Dictionary. Use instead
var rows: [[String : AnyObject]] = [[:]]
let firstLine: [String : AnyObject] = ["time": time, "Playing": false]
rows.append(firstLine)

Error when getting value from constant : Ambiguous reference to member 'subscript'

I am using enum and tuple with value of enum case. I've trouble with getting value from [String: String] constant.
I don't know how to fix it, it has to be a trap, but I don't know where, as the key is surely string:
enum DictTypes : String {
case settings
case options
case locations
}
enum FileTypes : String {
case json
case pList
}
func getCodebookUrlComponent() -> String
{
var FileSpecs: (
dictType: DictTypes,
fileType: FileTypes,
redownload: Bool
) = (.settings, .json, true)
let codebooks = [
"settings" : "settings",
"options" : "options"
]
let key = self.FileSpecs.dictType // settings or options
if let urlComponent = codebooks[key] {
return urlComponent
}
return ""
}
This line if let urlComponent = codebooks[key] comes with an error:
Ambiguous reference to member 'subscript'
You should use .rawValue for this case :
if let urlComponent = codebooks[key.rawValue]{
return urlComponent
}
This problem occurs because of the let key = self.FileSpecs.dictType in this line you receive key that is FileSpecs type. And subscript that is implemented in the Array will not conform for that value type.
rawValue in you're case return String value that you assign in you're enum.
Since value from enum case is surely string, I would type it like this:
let key = FileSpecs.dictType.rawValue // "settings" or "options"
or
let key = String(describing: FileSpecs.dictType)
return codebooks[key]!

Cannot subscript a value of type 'Dictionary<String, AnyObject>' with an index of type 'String'

I'm getting this error:
Cannot subscript a value of type 'Dictionary<String, AnyObject>' with an index of type 'String'
with the code below. I checked other posts with this error - they indicate that the dictional is an optional and must be unwrapped first - but in this case the dictionary is NOT wrapped - so I'm not sure what's wrong with it.
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
if let jsonArticleItems = jsonResult["response"]!["docs"]! as? [[String: AnyObject]] {
for jsonArticleItem in jsonArticleItems {
var feedArticleItem = FeedArticleItem()
feedArticleItem.identifier = jsonArticleItem["_id"] <-- ERROR HERE
Turned out I needed to cast the value of the dictionary entry:
feedArticleItem.identifier = jsonArticleItem["_id"]! as? String
The warning is NOT super useful

Swift: Cannot subscript a value of type 'Dictionary<String, NSObject>?'

EDIT: Not a DUPLICATE:
That solution gives 'Could not find an overload for 'subscript' that accepts the supplied arguments' error. So, no this is NOT a duplicate.
Here is the function declaration.
func auth(user: String, pass: String, completion: (returned: Bool, error: Bool, response: Dictionary<String, NSObject>?) -> ()){
response can be nil
}
Now I'm trying to access value passed back in another file and getting an error:
if let labelString = response["error_description"] as! String?{
self.labelPrompt.text = labelString
}
Error: Cannot subscript a value of type 'Dictionary?' with an index of type 'String'
It is a duplicate of the linked question: what you need is to unwrap the dictionary before using it with a subscript.
There's many ways ("if let", etc) and the linked answer gives the solution of using "optional binding" by adding a ? between the variable holding the dictionary and the subscript.
Example in a Playground:
var response: Dictionary<String, NSObject>? = nil
// NOTICE THE "?" BETWEEN THE VARIABLE AND THE SUBSCRIPT
if let labelString = response?["error_description"] as? String {
println(labelString) // not executed because value for key is nil
}
response = ["test":"yep"]
if let labelString = response?["test"] as? String {
println(labelString) // "yep"
}
Another way of unwrapping the dictionary:
if let responseOK = response, let test = responseOK["test"] as? String {
println(test) // "yep"
}