Reputation: 59
Ive tried for hours with every possible combination and can't get this to work.
my function:
func allItems() -> [TodoItem] {
let todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) ?? [:]
let items = Array(todoDictionary.values)
return items.map({TodoItem(
deadline: $0["deadline"] as! Date,
title: $0["title"] as! String,
UUID: $0["UUID"] as! String!,
description: $0["description"] as! String,
imageSavePath: ($0["imageSavePath"] as! String),
isItComplete: $0["isItComplete"] as! Bool
)}).sorted(by: {(left: TodoItem, right:TodoItem) -> Bool in
(left.deadline.compare(right.deadline) == .orderedAscending)
})
}
Gives me the error 'type 'Any' has no subscript members. I have researched and tried to alter:
func allItems() -> [TodoItem]
to
func allItems() -> [Any:[TodoItem]]
However this raises the error that 'Type Any does not conform to Hashable protocol'. Is this the right lines to go down?
Please help.....before my macbook goes out the window!
Upvotes: 1
Views: 434
Reputation: 47886
Take care of the types of the variables.
dictionary(forKey:)
returns [String: Any]
, so todoDictionary
is a [String: Any]
.
(In older Swift, Value type of generic dictionary was imported as AnyObject
, but now it's Any
.)
You are retrieving only values and making it to an Array, so items
is an Array<Any>
.
Then you are applying map
to items
, so $0
in it is an Any
.
Thus, you cannot apply any methods including subscript to Any
.
If you need to apply $0["deadline"]
or something and the values may differ, the type of $0
needs to be a Dictionary with its Key type String
and its Value type mixed, which is represented by Any
in Swift 3.
The type $0
needs to be [String: Any]
, so the type of items
needs to be Array<[String: Any]>
(aka [[String: Any]]
).
Which means the Value type of todoDictionary
needs to be [String: Any]
, its Key type is already constrained to String
, so the type of todoDictionary
needs to be [String: [String: Any]]
.
Conclusion, change the first line of your allItems()
to this:
let todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) as? [String: [String: Any]] ?? [:]
Upvotes: 2
Reputation: 63271
You're taking only the values
out of the dictionary. You're then trying to subscript these Any
instances with Strings, which won't work because the compiler has no idea if those Any
instances are guaranteed to be Dictionaries
or anything else that can be subscripted by a String
.
Your question is quite lacking and doesn't convert what you're actually trying to achieve. I suspect you're trying to map a [String: [String: Any]]
to a [String: TodoItem]
, here are your issues:
func allItems() -> [TodoItem] {
let todoDictionary = UserDefaults.standard.dictionary(forKey: ITEMS_KEY) ?? [:] //inferred type: [String: Any]
let items = Array(todoDictionary.values) //inferred type [Any]
return items.map({TodoItem(
deadline: $0["deadline"] as! Date, //[Any] can only be subscripted by indices, not by string.
title: $0["title"] as! String,
UUID: $0["UUID"] as! String!,
description: $0["description"] as! String,
imageSavePath: ($0["imageSavePath"] as! String),
isItComplete: $0["isItComplete"] as! Bool
)}).sorted(by: {(left: TodoItem, right:TodoItem) -> Bool in
(left.deadline.compare(right.deadline) == .orderedAscending)
})
}
Upvotes: 0