So I have JSON data that is formatted as a list of dictionaries, and I have it stored as an NSArray Object, but I'm unsure how to convert each entry into a dictionary object when it is currently AnyObject
The AnyObject data is already formatted like a JSON dictionary
Here is the code I used to create the Array
func startConnection(){
let urlPath: String = "http://api.mtgdb.info/search/omni"
var url: NSURL = NSURL(string: urlPath)!
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
self.data.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!){
var err: NSError
var jsonResult: NSArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSArray
for var i = 0; i<jsonResult.count; ++i{
...
}
}
I tried this sample code to solve your problem.
First of all run this "http://api.mtgdb.info/search/omni" URL in web browser and copy response then paste into "http://jsonlint.com", response is valid and I get array of 8 dictionaries, Like id: 37113, 39932, 83737, 106426, 228247, 288937, 382286, 386302 -- 8 data.
In Objective C, It works perfect and I get same result as web browser.
But in Swift, It behave weird, Can't parse whole respose, get only half dictionary as object of array. Only get this much part of response,
Printing description of jsonResult:
(
{
artist = "Arnie Swekel";
cardSetId = JUD;
cardSetName = Judgment;
colors = (
green,
white
);
convertedManaCost = 7;
description = "Trample\nPhantom Nishoba enters the battlefield with seven +1/+1 counters on it.\nWhenever Phantom Nishoba deals damage, you gain that much life.\nIf damage would be dealt to Phantom Nishoba, prevent that damage. Remove a +1/+1 counter from Phantom Nishoba.";
flavor = "";
formats = (
{
legality = Legal;
name = "Odyssey Block";
},
{
legality = Legal;
name = Legacy;
},
{
legality = Legal;
name = Vintage;
},
{
legality = Legal;
name = Freeform;
},
{
legal
I tried this sample of code
class ViewController: UIViewController, NSURLConnectionDelegate {
var data:NSMutableData!
var arrvehicls:NSMutableArray!
override func viewDidLoad() {
super.viewDidLoad()
self.data = NSMutableData()
self.arrvehicls = NSMutableArray()
self.startConnection()
}
func startConnection(){
let urlPath: String = "http://api.mtgdb.info/search/omni"
var url: NSURL = NSURL(string: urlPath)!
var request: NSURLRequest = NSURLRequest(URL: url)
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
connection.start()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
self.data.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
var err: NSError
var jsonResult:NSArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSArray
for var i = 0; i<jsonResult.count; ++i {
var dictResult = jsonResult.objectAtIndex(i) as! NSDictionary
var vehicleInfo = Vehicle()
vehicleInfo.id = dictResult.valueForKey("id") as! Int
vehicleInfo.artist = dictResult.valueForKey("artist") as! String
vehicleInfo.cardID = dictResult.valueForKey("cardSetId") as! String
vehicleInfo.cardName = dictResult.valueForKey("cardSetName") as! String
vehicleInfo.colors = dictResult.valueForKey("colors") as! NSArray
vehicleInfo.details = dictResult.valueForKey("description") as! String
vehicleInfo.flavour = dictResult.valueForKey("flavor") as! String
vehicleInfo.formats = NSMutableArray()
var arr = dictResult.valueForKey("formats") as! NSArray
for var j = 0; j<arr.count; ++i {
var dictFormats = arr.objectAtIndex(i) as! NSDictionary
var formats = Formats()
formats.legality = dictFormats.valueForKey("legality") as! String
formats.name = dictFormats.valueForKey("name") as! String
vehicleInfo.formats.addObject(formats)
}
self.arrvehicls.addObject(vehicleInfo)
}
}
}
Related
Trouble with JSON parsing in swift 1.2
I have an issue with the JSON parsing, i am not getting the correct data response for my parameters. i have been stuck on the issue for quite some time now. i don’t know how to fix it. i am new to iOS development. also i haven’t used any third party library.[Don’t know how to use them]
I am getting the right response for my very first iteration but for the next iteration results of previous iteration is added along with the new results. Like that each loop result is ended up with the results of previous iteration
My JSON SAMPLE.[can provide link, please let me know]
struct AssetItems {
var Name:String
var Desc:String
var Image:String
var entityId:String
var aFileType:String
var aFileSize:String
var aFileCreatedDate:String
var aFileRevisionDate:String
var aFileModifiedDate:String
var aProductName:String
var aVersion:String
var aAssetType:String
var aIsFolder:String
init(assetName:String,assetDescription:String,assetImage:String,entityId:String,FileType:String,FileSize:String,FileCretedDate:String,FileReveisionDate:String,FileModifiedDate:String,ProductName:String,Version:String,AssetType:String,IsFolder:String) {
self.Name = assetName
self.Desc = assetDescription
self.Image = assetImage
self.entityId = entityId
self.aFileType = FileType
self.aFileSize = FileSize
self.aFileCreatedDate = FileCretedDate
self.aFileRevisionDate = FileReveisionDate
self.aFileModifiedDate = FileModifiedDate
self.aProductName = ProductName
self.aVersion = Version
self.aAssetType = AssetType
self.aIsFolder = IsFolder
}
}
struct AssetModel {
var aName:String
var aDesc:String
var aCount:String
var aEntityId:String
var items:[AssetItems]
init(rackName:String,rackDescription:String,totalNoAssets:String,EntityId:String,rackItems:[AssetItems]) {
self.aName = rackName
self.aDesc = rackDescription
self.aCount = totalNoAssets
self.aEntityId = EntityId
self.items = rackItems
}
}
var assetData:Array<AssetModel> = Array<AssetModel>()
var assetContents:Array<AssetItems> = Array<AssetItems>()
THIS IS HOW I AM PARSING JSON
func get_data_from_Url(url:String) {
let url = NSURL(string: url)
var request:NSMutableURLRequest = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content_Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var responseError : NSError?
var response : NSURLResponse?
var urlData: NSData? = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &responseError)
if(urlData != nil) {
var responseData:NSString = NSString(data: urlData!, encoding: NSUTF8StringEncoding)!
let res = response as! NSHTTPURLResponse
var err:NSError?
if (res.statusCode == 200)
{
var parseError: NSError?
let json:AnyObject = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &err) as AnyObject!
if (parseError == nil) // no error while parsing
{
if let Asset_list = json as? NSArray
{
for (var i = 0; i < Asset_list.count ; i++ )
{
if let Asset_obj = Asset_list[i] as? NSDictionary
{
if let AssetGroupName = Asset_obj["Name"] as? String
{
if let AssetGroupDescription = Asset_obj["Description"] as? String
{
if let entityId = Asset_obj["EntityId"] as? String
{
if let totalAssets = Asset_obj["_NoOfAssets"] as? String
{
if let items = Asset_obj["Items"] as? NSArray
{
for (var j=0 ; j < items.count; j++)
{
if let asset_items = items[j] as? NSDictionary
{
if let AbsolutePath = asset_items["AbsolutePath"] as? String
{
if let Description = asset_items["_Description"] as? String
{
if let Name = asset_items["_Name"] as? String {
if let entityId = asset_items["EntityId"] as? String
{
if let FileType = asset_items["_FileType"] as? String
{
if let FileSize = asset_items["_FileSize"] as? String
{
if let FileCreatedDate = asset_items["CreatedDate"] as? String
{
if let FileModifiedDate = asset_items["ModifiedDate"] as? String
{
if let RevisionDate = asset_items["RevisionDate"] as? String
{
if let productName = asset_items["ProductName"] as? String
{
if let version = asset_items["Version"] as? String
{
if let AssetType = asset_items["_AssetType"] as? String
{
if let isFolder = asset_items["IsFolder"] as? String
{
var add = AssetItems(assetName: Name, assetDescription: Description, assetImage: AbsolutePath, entityId: entityId, FileType: FileType, FileSize: FileSize, FileCretedDate: FileCreatedDate, FileReveisionDate: RevisionDate, FileModifiedDate: FileModifiedDate, ProductName: productName, Version: version, AssetType: AssetType, IsFolder: isFolder)
assetContents.append(add)
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
var add_it = AssetModel(rackName: AssetGroupName, rackDescription: AssetGroupDescription, totalNoAssets: totalAssets, EntityId: entityId, rackItems: assetContents)
assetData.append(add_it)
}
}
}
}
}
}
}
}
}
}
}
do_table_refresh()
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(),
{
self.tableView.reloadData()
})
return
}
My Output
Please some one help me fix this, Any suggestion will also do.
THANKS
Special thanks to #SMi, With his GuidLines i was able to solve my issue.
I knew that i had to clear the inner array at the end of the loop[But,didn't knew how to clear that.]
var add_it = AssetModel(rackName: AssetGroupName, rackDescription: AssetGroupDescription, totalNoAssets: totalAssets, EntityId: entityId, rackItems: assetContents)
assetData.append(add_it)
assetContents.removeAll()
All i had to do is use the .removeAll() method to clear the assetContents Array.
I am using following Class to receive data from an external database:
import Foundation
protocol HomeModelProtocal: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, NSURLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocal!
var data : NSMutableData = NSMutableData()
var mi_movil: String = ""
let misDatos:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var urlPath: String = "http:...hidden here.."
let parametros = "?id="
func downloadItems() {
mi_movil = misDatos.stringForKey("ID_IPHONE")!
print ("mi_movil en HOMEMODEL:",mi_movil)
urlPath = urlPath + parametros + mi_movil
let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
print ("LA URL ES: ",url)
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithURL(url)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data);
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
do{
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
let locations: NSMutableArray = NSMutableArray()
for(var i = 0; i < jsonResult.count; i++)
{
jsonElement = jsonResult[i] as! NSDictionary
print (jsonElement)
let location = MiAutoModel()
//the following insures none of the JsonElement values are nil through optional binding
if let id_mis_autos = jsonElement["id_mis_autos"] as? String,
let modelo = jsonElement["modelo"] as? String,
let ano = jsonElement["ano"] as? String,
let id_movil = jsonElement["id_movil"] as? String
{
location.id_mis_autos = id_mis_autos
location.modelo = modelo
location.ano = ano
location.id_movil = id_movil
}
locations.addObject(location)
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.delegate.itemsDownloaded(locations)
})
}
}
If there are received data, it works fine but if there are no data an exception is thrown:
Could not cast value of type '__NSArray0' (0x1a0dd2978) to 'NSMutableArray' (0x1a0dd3490)
What should I change to detect if there are no data to avoid the exception?
Since you don't seem to be modifying jsonResult anywhere, the obvious choice is to make it an NSArray instead of an NSMutableArray, and change the downcasting to match that.
I'm not sure why you're using NSDictionary and NSMutableArray but this is how I would do it:
for result in jsonResult {
guard let jsonElement = result as? [String:AnyObject] else { return }
let locations: [MiAutoModel] = []
let location = MiAutoModel()
//the following insures none of the JsonElement values are nil through optional binding
let id_mis_autos = jsonElement["id_mis_autos"] as? String ?? ""
let modelo = jsonElement["modelo"] as? String ?? ""
let ano = jsonElement["ano"] as? String ?? ""
let id_movil = jsonElement["id_movil"] as? String ?? ""
location.id_mis_autos = id_mis_autos
location.modelo = modelo
location.ano = ano
location.id_movil = id_movil
locations.append(location)
}
You might have to change some of the code depending on your situation.
I am trying the get the preview link from the itunes search api. I have a function that will get the information when the button is clicked, but the function is not being called. I want to get the preview link of the first object in the results array How do I fix this?
var d: NSMutableData = NSMutable Data()
var tData: NSArray = NSArray()
func ctn(receivedResponse: NSURLConnection!, receivedResponse response: NSURLResponse!) {
// clear out the data object if a new request was received.
self.d = NSMutableData()
}
func ctn(ctn: NSURLConnection!, receivedData d: NSData!) {
self.d.appendData(d)
}
func ctnFinishedLoading(ctn: NSURLConnection!) throws {
var err: NSError
var jResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(d, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if jResult.count>0 && jResult["results"]!.count>0 {
var results: NSArray = jResult["results"]as! NSArray
self.tData = results
print(tData)
//self.appsTableView.reloadData()
}
}
func playit(sender: UIButton!) {
let cell = table.dequeueReusableCellWithIdentifier("cell")
let playButtonrow = sender.tag
print(ret[playButtonrow])
let searchTerm: String = ret[playButtonrow]
let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)
if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
let url: NSURL = NSURL(string: urlPath)!
let request: NSURLRequest = NSURLRequest(URL: url)
let ctn: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false)!
print("Search iTunes API at URL \(url)")
ctn.start()
}
The way to grab the previewUrl is to grab the value for a single result array member such as the first one having index 0 and then pulling the value for the previewUrl key. For example:
if jResult.count>0 && jResult["results"]!.count>0 {
var results: NSArray = jResult["results"]as! NSArray
if let previewUrl = results[0]["previewUrl"] {
print(previewUrl!)
}
}
Since NSURLConnection is deprecated in iOS 9, I'll also give you a way of using NSURLSession to retrieve the previewUrls from the iTunes API.
let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music"
let url: NSURL = NSURL(string: urlPath)!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) -> Void in
do {
if let dict: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
{
// The search is complete.
for result in dict["results"] as! NSArray {
if let previewUrl = result["previewUrl"] {
print(previewUrl!)
}
}
}
} catch let jsonError as NSError {
// Handle error.
}
}
task.resume()
I am creating a weather app with Swift. So I have retrieved the JSON data and stored it in a dictionary:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
///////getting URL:
let mainAddress = NSURL(string: "https://...") //for NY
//Now, getting the data syncronously by creating a session object::
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask =
sharedSession.downloadTaskWithURL(mainAddress!, completionHandler: {
(location:NSURL!, response:NSURLResponse!, error: NSError!) -> Void in
//using the if statement to avoid crashing when the URL is wrong.
if error == nil {
//Now, creating a dataObject for the task:
let dataObject = NSData(contentsOfURL: location)
//getting a formated dictionary of the data from URL:
let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as NSDictionary //added '!' to NSdata for now
}
})
downloadTask.resume()
I have used a Struct, in a difirent file, in order to organize and initialize the dictionary's data:
import Foundation
import UIKit
import WatchKit
//created the struct just to better organize the data. In the future, if the API keys change, it would be easier to ajust the code, rather than if the data was directly read from the API onto the graph.
struct hourlyData {
///declaring only keys that have Integers as value.
var daylyPop0 : Int
var daylyPop1 : Int
var daylyPop2 : Int
var daylyPop3 : Int
var daylyPop4 : Int
var summaryNowDay : String
var summaryNowNight : String
var iconNow : String
var currentTime: String?
//Initializing the values here. With optional properties:
init(weatherDictionary:NSDictionary){
daylyPop0 = weatherDictionary["daily0_pop"] as Int
daylyPop1 = weatherDictionary["daily1_pop"] as Int
daylyPop2 = weatherDictionary["daily4_pop"] as Int
daylyPop3 = weatherDictionary["daily3_pop"] as Int
daylyPop4 = weatherDictionary["daily2_pop"] as Int
}
Now, I am implementing a chart for it. So I need to access the values from the dictionary in order to implement them on the chart. However, I've been unsuccessfull after many attemps.
The code lets me access the hourlyData struct, but not the weatherDictionary, since it was declared inside the session declaration.
Anyone knows an effective way to do it?
Any tips would be appreciated, thanks.
Try this for asynchronous request:
var request = NSURLRequest(URL: url)
var dict = NSDictionary()
var yourSavedData = hourlyData()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) { (response, data, error) -> Void in
if data == nil
{
println("Error in connection")
return
}
var error = NSErrorPointer()
dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: error) as NSDictionary
if error != nil
{
println(error.debugDescription)
return
}
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
if let yourDict = dict as? NSDictionary
{
yourSavedData = hourlyData(yourDict!)
}
}
})
Not tested, but should work.
You need to use if let to parse dictionary.
Alright, so after the answers you guys posted I've updated the code a little. This is how the viewDidLoad looks like:
override func viewDidLoad() {
super.viewDidLoad()
///////getting URL:
let url = NSURL(string: "http://..........") //for NY
var request = NSURLRequest(URL: url!)
var dict = NSDictionary()
var yourSavedData = hourlyData(weatherDictionary: NSDictionary())
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue()) { (response, data, error) -> Void in
if data == nil
{
println("Error in connection")
return
}
var error = NSErrorPointer()
dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: error) as! NSDictionary
if error != nil
{
println(error.debugDescription)
return
}
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
if let yourDict = dict as? NSDictionary
{
yourSavedData = hourlyData(weatherDictionary: yourDict)
}
}
})
And this is how the other swift file with the Struct looks like:
struct hourlyData {
///declaring only keys that have Integers as value.
var daylyPop0 : Int
var daylyPop1 : Int
var daylyPop2 : Int
var daylyPop3 : Int
var daylyPop4 : Int
var summaryNowDay : String
var summaryNowNight : String
var iconNow : String
var currentTime: String?
//Initializing the values here. With optional properties:
init(weatherDictionary:NSDictionary){
daylyPop0 = weatherDictionary["hourly10_pop"] as! Int
daylyPop1 = weatherDictionary["hourly11_pop"] as! Int
daylyPop2 = weatherDictionary["hourly12_pop"] as! Int
daylyPop3 = weatherDictionary["hourly13_pop"] as! Int
daylyPop4 = weatherDictionary["hourly14_pop"] as! Int
summaryNowDay = weatherDictionary["today_day_fcttext_metric"] as! String
summaryNowNight = weatherDictionary["today_night_fcttext_metric"] as! String
iconNow = weatherDictionary["current_icon"] as! String
let currentTimeIntValue = weatherDictionary["forecast_time"] as! Int
currentTime = dateStringFromUnixTime(currentTimeIntValue)
}
//Converting unixTime to a desired style:::used ShortStyle in this case:
func dateStringFromUnixTime(unixTime: Int) -> String{
let timeInSeconds = NSTimeInterval(unixTime)
let weatherDate = NSDate(timeIntervalSince1970: timeInSeconds)
let dateFormatter = NSDateFormatter()
dateFormatter.timeStyle = .ShortStyle
return dateFormatter.stringFromDate(weatherDate)
}
}
Now the code looks fine, and it does not show any error, besides a warning under the 'if let', which says: Conditional cast from 'NSDictionary' to 'NSDictionary' always succeeds.
When I run the simulator, it crashes and displays: fatal error: unexpectedly found nil while unwrapping an Optional value. Highlighting, in green, the code line: daylyPop0 = weatherDictionary["hourly10_pop"] as! Int
I have this Swift code:
func getData(completion: (array: Array<AnyObject>)->Void) {
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let session: NSURLSession = NSURLSession(configuration: sessionConfiguration)
var request: NSURLRequest = NSURLRequest(URL: NSURL(string: "http://coinabul.com/api.php"))
let task: NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if !error {
let httpResp: NSHTTPURLResponse = response as NSHTTPURLResponse
if httpResp.statusCode == 200 {
var json: NSDictionary = self.convertDataToJSON(data)
var myArray: Array = Array<Currency>()
for (key: AnyObject, object: AnyObject) in json {
let info: NSDictionary = object as NSDictionary
let grams: CGFloat = info["Grams"] as CGFloat
let ounces: CGFloat = info["Ounces"] as CGFloat
let usd: CGFloat = info["USD"] as CGFloat
// Do something with those values
}
}
}
})
task.resume()
}
func convertDataToJSON(data: NSData) -> NSDictionary {
var error: NSError?
var jsonDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &error) as NSDictionary
return jsonDictionary
}
The "json" NSDictionary is correct. If I print it:
{
BTC = {
Grams = "15.398340412292";
Ounces = "0.49506814017307";
SilverGrams = "1010.0959168583";
SilverOunces = "32.475337832916";
USD = "624.825500000000";
};
Gold = {
Grams = "0.06494206341493";
Ounces = "2.0199239627704";
USD = "1262.100000000000";
};
Silver = {
Grams = "0.0009900049917623401";
Ounces = "0.030792597293164";
USD = "19.240000000000";
};
}
I can do json["Silver"] and get the corresponding object. But if I try to do json["Silver"]["USD"] my app crashes.
What am I missing here?
The expression:
json["Silver"]
returns AnyObject? which doesn't allow [] because it's unknown what it is, so you have to typecast it for further reference. Note that Xcode will currently crash if you try to do this in a workspace
json["Silver"] as? Dictionary
You can string it all together using optional chaining, as:
(json["Silver"] as? NSDictionary)?["USD"]
Note that the result of indexing operations are almost always optionals, and optional chaining means this one is definitely going to be optional, so you'll have to deal with checking and unwrapping.