user1107173 user1107173 - 4 months ago 29
Swift Question

Swift: flatMap to Dictionary

I am trying to parse the following JSON:

{
"String For Key 1": [
"http://www.urlToSomePathA.jpg",
"http://www.urlToSomePathB.jpg",
"http://www.urlToSomePathC.jpg",
],
"String For Key 2": [
"http://www.urlToSomePathD.jpg",
"http://www.urlToSomePathE.jpg",
"http://www.urlToSomePathF.jpg"
],
"String For Key 3": [
"http://www.urlToSomePathG.jpg",
"http://www.urlToSomePathH.jpg",
"http://www.urlToSomePathI.jpg",
],
"String For Key 4": [
"http://www.urlToSomePathJ.jpg",
"http://www.urlToSomePathK.jpg",
"http://www.urlToSomePathL.jpg"
],
"String For Key 5": [
"http://www.urlToSomePathM.jpg",
"http://www.urlToSomePathN.jpg",
"http://www.urlToSomePathO.jpg"
],
"String For Key 6": [
"http://www.urlToSomePathP.jpg",
"http://www.urlToSomePathQ.jpg",
"http://www.urlToSomePathR.jpg"
]
}


I am also following this tutorial. It's on Github in Playground

In the example, they are parsing an
Array
of dictionaries using
typealias JSONDictionary = [String: AnyObject]


I need to parse a
Dictionary
that has a
Key
which is
String
, and
Value
that is an
Array
. Hence:
typealias JSONDictionary = [String: [AnyObject]]
and I am getting an error when returning a
flatMap
.

extension Resource {
init(url: NSURL, parseJSON: AnyObject -> A?) {
self.url = url
self.parse = { data in
let json = try? NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: [AnyObject]]
//This is where I get an error
return json.flatMap(parseJSON)
}
}
}


Error:

Cannot convert value of type `AnyObject -> A? to expected argument type `([String: [AnyObject]]?) -> _?


How can I get a dictionary with
Keys
as
String
and
Values
as an
Array
? I would like to keep their
Generic
approach.

Answer

Type of jsonString is Dictionary<String, Array<String>> You can give it a type like Dictionary<String, AnyObject>

AnyObject can contain class and struct i.e Array, Dictionary, String, Int, Obj C Classes Hence an Array<String> is represented by AnyObject not [AnyObject]

let jsonString:[String: AnyObject] =
[
    "String For Key 1": [
    "http://www.urlToSomePathA.jpg",
    "http://www.urlToSomePathB.jpg",
    "http://www.urlToSomePathC.jpg",
    ],
    "String For Key 2": [
    "http://www.urlToSomePathD.jpg",
    "http://www.urlToSomePathE.jpg",
    "http://www.urlToSomePathF.jpg"
    ]
]

// Now you can map a function on the value type
let values = jsonString.flatMap { $0.1 as? [String] }
print(values)
// RESULT: [["http://www.urlToSomePathA.jpg", "http://www.urlToSomePathB.jpg", "http://www.urlToSomePathC.jpg"], ["http://www.urlToSomePathD.jpg", "http://www.urlToSomePathE.jpg", "http://www.urlToSomePathF.jpg"]]

Update

let keys = jsonString.flatMap { $0.0 } // ["String For Key 1", "String For Key 2"]

As commented by @dffri, you can use keys property on dictionary which will return LazyMapCollection which will realise only if you access the object inside.

let keys = jsonString.keys