Reputation: 5194
I have a question regarding when to use NSDictionary & when to use NSArray while you are making a HTTP request and getting JSON data back.
For example if the JSON coming back is an array of objects like below:
[
{object1},
{object2},
.........
]
I have the following line in my code:
if let books:Array<AnyObject> = json[""] as? Array<AnyObject> {
}
Its giving an error:
Array< anyObject >? is not convertible to Array< anyObject >
Parsing:
var json:NSMutableArray = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSMutableArray
if (jsonError != nil) {
println("Error parsing json: \(jsonError)")
}
Any idea what I might be doing wrong.
UPDATE:
Currently I have the following code:
class func getBooks(completion: (result:Array<BookSummary>)->()) {
var bookArray = [BookSummary]()
let url = NSURL(string: "http://something.herokuapp.com/user/all")
if let tempUrl:NSURL = url {
let urlReq = NSURLRequest(URL: tempUrl)
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(urlReq, queue: queue, completionHandler: { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
if (error != nil) {
println("API error: \(error), \(error.userInfo)")
}
var jsonError:NSError?
var newBook = BookSummary(id: "", title: "", fullname: "", thumbnail: "")
if let arr = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [AnyObject] {
for a in arr {
//println(a)
//println( arr[0])
println( arr[0])
}
}
By doing println(arr[0])
I am getting the object at the first index.
But if I try println(arr[0].fullname)
it comes up with an error:
any object does not have a member named fullname
Upvotes: 1
Views: 1064
Reputation: 1262
To parse this json data from CDiscount API which contains Products/Price/Name :
{
"ItemCount": "34",
"PageCount": "7",
"PageNumber": "0",
"Products": [
{
"AssociatedProducts": null,
"BestOffer": {
"Condition": "New",
"Id": "MD531NFA",
"IsAvailable": true,
"PriceDetails": {
"Discount": null,
"ReferencePrice": "249.00",
"Saving": {
"Type": "Amount",
"Value": "17.0"
}
},
"ProductURL": "http://www.cdiscount.com/opa.aspx/?trackingid=T1mQnsY6DVL2nQMfDBv95HJiDedNp6Iusby9wMMBIWJ8xCUTe2ax25EOmRJ_4IkI&action=product&id=MD531NFA",
"SalePrice": "231.98",
"Seller": {
"Id": "0",
"Name": "Cdiscount"
},
"Shippings": null,
"Sizes": null
},
"Brand": "APPLE",
"Description": "Tablette tactile avec écran 7,9\" capacitif - Processeur Apple A5 bicoeur - Stockage 16Go - WiFi 802.11 b/g/n - Camera avant 1,2Mpixels - Caméra arrière 5Mpixels - Connecteur Lightning reversible - Jusqu’à 10h d'autonomie - IOS 6 - Garantie 1 an",
"Ean": null,
"Id": "MD531NFA",
"Images": null,
"MainImageUrl": "http://i2.cdscdn.com/pdt2/N/F/A/1/300x300/MD531NFA.jpg",
"Name": "Apple iPad mini Wi-Fi 16 Go blanc & argent",
"Offers": null,
"OffersCount": "10",
"Rating": "4.69"
}
]
}
From this data, I wanted to print the product name and its price. So I should first parse in the Json object as dictionary in search for 'Products' key, and the results as an AnyObject.
let products: AnyObject = jsonDict["Products"]
Then loop through all products and for each one loop over the dictionary keys
for aProduct in products as! NSArray{
for aKey in (aProduct as! NSDictionary).allKeys{
Based on the json data model, it's enough to print the product name :
if aKey as! String == "Name"{
if let name: AnyObject = aProduct["Name"]{
println("Product : \(name) ->")
}
}
But I need to go deeper in the data tree to print the price as it is stored in another dictionary of dictionary.
if aKey as! String == "BestOffer"{
if let offers: AnyObject = aProduct["BestOffer"]{
for offerDetail in (offers as! NSDictionary).allKeys{
if offerDetail as! String == "SalePrice"{
if let price: AnyObject = offers["SalePrice"]{
println("|--> Price: \(price)")
}
}
}
}
}
So to resume :
// Get data in a swift Dictionary
let jsonDict = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.AllowFragments, error: nil) as? [String: AnyObject]
// Begin navigate through the dictionary (here through 'Products')
if let products: AnyObject = jsonDict["Products"]{
// Get product data through loop in a NSArray
for aProduct in products as! NSArray{
// Loop over keys in one product as NSDictionary
for aKey in (aProduct as! NSDictionary).allKeys{
// test key value
if aKey as! String == "Name"{
// if exists, print product name
if let name: AnyObject = aProduct["Name"]{
println("Product : \(name) ->")
}
}
// another test key value
if aKey as! String == "BestOffer"{
// same as before to get deeper in the json tree structure
if let offers: AnyObject = aProduct["BestOffer"]{
for offerDetail in (offers as! NSDictionary).allKeys{
if offerDetail as! String == "SalePrice"{
if let price: AnyObject = offers["SalePrice"]{
println("|--> Price: \(price)")
}
}
}
}
}
}
}
}
Hope this will help !
Upvotes: 1
Reputation: 39081
If you are using the standard NSJSONSerialization
to parse from JSON string you use the JSONObjectWithData() class function.
This returns AnyObject? and can be parsed to either Dictionary or Array.
So if the JSON string starts with "[" its parseable to an Array:
if let arr = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [AnyObject] {
for a in arr {
println(a)
}
// Other options to access the values
println( arr[0] )
println( arr.first )
}
And if it starts with a "{" its parseable to a Dictionary:
if let dict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as? [String:AnyObject] {
for (key, value) in dict {
println("\(key) = \(value)")
}
// Other options to access the values
println( dict["someKey"] )
println( dict[dict.keys[0]] )
println( dict[dict.keys.first] )
}
In Swift I recommend you dont use NSDictionary and NSArray and use Swifts own Dictionary and Array instead. Mostly because Swift is so type safe and you can control the types on a Swift Dictionary and Array and not the old NS stuff.
Upvotes: 1
Reputation: 1896
Reading your comment, i think you want to look at AFNetworking.
Simple example:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"http://example.com/resources.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
// here is where you import the JSON data from responseObject
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
NSDictionary
is unsorted, but associative where as NSArray
is sorted but index only. One way is to obtain all the keys of the JSON
data into an NSArray
so the order of the data structure is maintained, then import the data into NSDictionary
. Then you can use the value from the keys array to reference the NSDictionary
The example is for Objective-C, however hopefully it will still be relevant
Upvotes: 0