I'm using RxSwift to help me achieve asynchronous HTTP requests in my osx application. My HTTP requests are modeled as a stream that returns an Observable<Any?>
. The Any?
value that is returned is a jsonObject created from the data received in the HTTP response:
let data = try? JSONSerialization.jsonObject(with: data)
return Observable.just(data)
After making an HTTP request, I then subscribe to the stream, waiting for the next value to arrive. After it arrives, I save the data as a [String: Any]
before proceeding:
let onNextSubscription = httpResponse?.subscribe(onNext: { data in
if let data = data as? [String: Any] {
print(data)
...
}
}
In this scenario, I am evaluating a CheckVersion method in my application to ensure that it is of a version that is currently supported. To accomplish this, I call out to a service that sends back JSON data regarding which versions of the application are currently supported and where to find them on the web if the evaluation fails. I then use data from the response in conjunction with data from within the app to evaluate whether or not the application is supported and proceed accordingly. That is, I will compare the "minVersion" value from the JSON data with the app's version to determine the result of the CheckVersion method.
The data I receive from the HTTP response is:
["status": 0, "result": {
"minVersion":"1.7.0",
"currVersion":"2.0.0",
"urls":{
"2.0.0":"/downloads/app.2.0.0.exe",
"1.9.0":"/downloads/app.1.9.0.exe",
"1.8.0":"/downloads/app.1.8.0.exe",
"1.7.0":"/downloads/app.1.7.0.exe",
}
}]
My next step is to retrieve the "minVersion" value from the data, so I continue within the same if {...}
block shown above:
let result = data["result"] as? [String: Any]
print(result)
let minVersion = result["minVersion"] as? String
print(minVersion)
...
What I expect to be able to do is access the value as result["minVersion]
before executing my version comparison logic; however, I am unable to, because data["result"] == nil
after it is downcast to [String: Any]
.
When data["result"]
is forcibly downcast to [String: Any]
, I receive the following error:
Could not cast value of type '__NSCFString' to 'NSDictionary'.
I'm not sure why this is going on as other posts I've seen around the web have shown that this is a normal means of accessing nested JSON data, although maybe I'm missing something.
My best guess is that it has to do with the fact that result["urls"]
values contains a jsonObject of its own, while result
's other values are simply strings.
Here are some of documents that I referenced while modeling my code:
I'm a C# .NET developer by trade, and this is my first foray into OS X and Swift world, so thanks in advance for the help and for bearing with me on this!
Edit: Here is the result of print(data["result"]):
Optional({
"minVersion":"1.7.0",
"currVersion":"2.0.0",
"urls":{
"2.0.0":"/downloads/app.2.0.0.exe",
"1.9.0":"/downloads/app.1.9.0.exe",
"1.8.0":"/downloads/app.1.8.0.exe",
"1.7.0":"/downloads/app.1.7.0.exe",
}
})
Edit: As per Dan's request, I tried the method outlined in https://stackoverflow.com/questions/30480672/....
let subNext = httpResponse?.subscribe(onNext: { data in
if let data = data as? [String: Any] {
print(data)
let result = self.convertToDictionary(text: data["result"] as! String)
print(result)
}
})
The result is:
Optional(["currVersion": 2.0.0, "urls": {
"1.7.0" = "/downloads/app.1.7.0.exe",
"1.8.0" = "/downloads/app.1.8.0.exe",
"1.9.0" = "/downloads/app.1.9.0.exe",
"2.0.0" = "/downloads/app.2.0.0.exe",
}, "minVersion": 1.7.0])
Final Edit
Thanks to Rob and Dan in the comments, I was able to solve my problem. It was essentially the same as shown in https://stackoverflow.com/questions/30480672/...
I'll go ahead and flag this one as a duplicate.