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
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.
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 !
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
Related
{
"status": true,
"status_code": 1,
"content": [
{
"cat_id": "3",
"cat_name": "Food",
"cat_parentid": "2"
},
{
"cat_id": "4",
"cat_name": "Entertainment",
"cat_parentid": "2"
},
{
"cat_id": "5",
"cat_name": "Cars",
"cat_parentid": "2"
},
{
"cat_id": "12",
"cat_name": "Personal Care",
"cat_parentid": "2"
}
],
"message": "Success"
}
UPDATE
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
completion((json as? AnyObject)!) //here completion callback will return the jsonObject to my UIViewController.
}
} catch let error {
print(error.localizedDescription)
}
this is my JSONObject. I am very new to the swift. how to get the content JSONArray and further process in swift.? Anybody can help me? Help will be appreciated.
This code checks if the status is true, gets the array for key content and prints all values in the array.
The array is clearly [[String:String]] so cast the object to this specific type.
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let status = json["status"] as? Bool, status == true {
if let content = json["content"] as? [[String:String]] {
for category in content {
let id = category["cat_id"]
let name = category["cat_name"]
let parentId = category["cat_parentid"]
print(id , name, parentId)
}
}
}
}
} catch let error {
print(error.localizedDescription)
}
PS: As always, never use .mutableContainers in Swift. It's meaningless
Check whether your json has content array
if let content = json["content"] as? [Dictionary<String, AnyObject>] {
print(content) // it will give you content array
}
Get content array like this:
let allContent = json["content"] as? [[String: Any]]
Full sample:
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
if let allContent = json["content"] as? [[String: Any]] {
for content in allContent {
let catId = content["cat_id"] as? String
let catName = content["cat_name"] as? String
let catParentId = content["cat_parentid"] as? String
print(">> catid=" + catId!)
print(">> catName=" + catName!)
print(">> catparentID=" + catParentId!)
}
}
}
} catch let error {
print(error.localizedDescription)
}
let content = dict.objectForKey("content")! as NSArray
Then you can get json of single object for parsing by
for var cat in content
{
print(cat)
}
Another alternative way, by using the library.
First, import JSON library for Swift - SwiftyJSON and use the code:
import SwiftyJSON
let json = JSON(<jsonObject data>)
let contentArray: Array<JSON> = json["content"].arrayValue
Library Integration
If you're using cocoapods then use this pod:
pod 'SwiftyJSON'
OR else just drag SwiftyJSON.swift to the project tree.
you can extract you data by providing key
if let array = result["content"] as? Array<AnyObject> {
print(arry)
}
You can access like below
if let filePath = Bundle.main.path(forResource: "sample", ofType: "json"), let data = FileManager().contents(atPath: filePath) {
do {
let dicRes = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
let contentArray = dicRes?["content"]
print("contentArray == \(contentArray)")
} catch {
}
}
I want to get my CampaignList from JsonObject which I parsed before. But it gives fatal error while it is running.
Error
"fatal error: unexpectedly found nil while unwrapping an Optional value"
self.CampaignArray = Campaigns as! NSMutableArray
The code :
var CampaignArray:NSMutableArray = []
func Get(){
let res: String = ""
let jsonObject = ["PhoneNumber": "xxxxx"]
let Jsn = JsonClass(value: jsonObject, text: res)
Alamofire.request(.POST, "http://MYURL",parameters: jsonObject,
encoding: .JSON).validate(statusCode: 200..<303)
.validate(contentType: ["application/json"])
.responseJSON { (response) in
NSLog("response = \(response)")
switch response.result {
case .Success:
guard let resultValue = response.result.value else {
NSLog("Result value in response is nil")
//completionHandler(response: nil)
return
}
let responseJSON = resultValue
print(responseJSON)
let result = Jsn.convertStringToDictionary(responseJSON as! String)!
print("result: \(result)")
let Campaigns = (result as NSDictionary)["Campaigns"]
print(Campaigns)
self.CampaignArray = Campaigns as! NSMutableArray
let notifications = (result as NSDictionary)["Notifications"]
print(notifications)
break
case .Failure(let error):
NSLog("Error result: \(error)")
// Here I call a completionHandler I wrote for the failure case
return
}
}
}
And my response Json is:
json: {"CampaignList":[
{"Bonus":"5","CampaignId":"zQUuB2RImUZlcFwt3MjLIA==","City":"34"}
{"Bonus":"3","CampaignId":"VgYWLR6eL2mMemFCPkyocA==","City":"34"}],
"MemberId":"ZBqVhLv\/c2BtMInW52qNLg==",
"NotificationList":[{"Notification":"Filiz Makarnadan Milli Piyango Çekiliş Hakkı Kazanmak İster misin ?","PhoneNumber":"555555555"}]}
JSON you provide is invalid. There is lack of , in Campaigns dictionary.
Valid JSON looks like:
{
"CampaignList": [
{
"Bonus": "5",
"CampaignId": "zQUuB2RImUZlcFwt3MjLIA==",
"City": "34"
},
{
"Bonus": "3",
"CampaignId": "VgYWLR6eL2mMemFCPkyocA==",
"City": "34"
}
],
"MemberId": "ZBqVhLv/c2BtMInW52qNLg==",
"NotificationList": [
{
"Notification": "Filiz Makarnadan Milli Piyango Çekiliş Hakkı Kazanmak İster misin ?",
"PhoneNumber": "555555555"
}
]
}
fatal error: unexpectedly found nil while unwrapping an Optional value
You receive this error because you try cast nil to NSDictionary object.
You have no Campaigns key in JSON you provide, so when you try to get this key from JSON you get nil. In next step you try cast this nil to NSDictionary.
Try use CampaignList key to get data you want.
let result: [String: AnyObject] = Jsn.convertStringToDictionary(responseJSON as! String)!
let campaigns: [Campaign] = result["CampaignList"] as! [Campaign]
print(Campaigns)
self.CampaignArray = campaigns
let notifications = result["NotificationList"]
print(notifications)
The same case will be with your Notifications key from JSON Dictionary.
You should also use swift types over objective-c NSDictionary and NSArray.
Try to use SwiftyJSON (https://github.com/SwiftyJSON/SwiftyJSON)
This library (pod) is very simple and has detailed documentation.
Your example:
I put son file "data.json" in my project and read it. Thank Daniel Sumara for your json example correction.
if let path = NSBundle.mainBundle().pathForResource("data", ofType: "json") {
if let data = NSData(contentsOfFile: path) {
let json = JSON(data: data)
if let CampaignList = json["CampaignList"].array {
for index in 0 ..< CampaignList.count {
print("Campaign [\(index)]")
if let CampaignId = CampaignList[index]["CampaignId"].string {
print(" CampaignId: \(CampaignId)")
}
if let City = CampaignList[index]["City"].string {
print(" City: \(City)")
}
if let Bonus = CampaignList[index]["Bonus"].string {
print(" Bonus: \(Bonus)")
}
}
}
if let MemberId = json["MemberId"].string {
print("MemberId: \(MemberId)")
}
if let NotificationList = json["NotificationList"].array {
print("NotificationList")
for notification in NotificationList {
if let Notification = notification["Notification"].string {
print(" Notification: \(Notification)")
}
if let PhoneNumber = notification["PhoneNumber"].string {
print(" PhoneNumber: \(PhoneNumber)")
}
}
}
}
}
Also you can use Alamofire-SwiftyJSON (https://github.com/SwiftyJSON/Alamofire-SwiftyJSON)
P.S. you have fatal errors because you do not check if value is nil. read about "if let" expression (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html)
I need to get values from a multistage JSON response.
For my login I get the following JSON data from my server:
{
"status": "...",
"payloadList": [
{
"type": "...",
"authToken": "...",
"user": {
"id": ...,
"firstName": "...",
...
}
}
]
}
to get the value firstName I tried the following:
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
if let payload = (json["payloadList"] as? [AnyObject]){
NSLog("Payload: %#", payload);
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
Since it's multistage, I convert it into string: anyobject and not dictionary.
The payload looks now like this:
payload: (
{
authToken = ...;
type = ...;
user = {
id = ...;
firstName = ...;
...
};
}
)
To get the first name I should now go through the anyobject.
Unfortunately this doesn't work:
if let user = (payload["user"] as? [AnyObject]){
NSLog("user: %#", user);
}
does someone know how to get the firstname out of it by go through the anyobject or does someone have an other solution from scratch by not using anyobject?
thanks a lot!
Your payload is an array of AnyObject objects. So you have to access to its objects by index. Try this variant:
for payloadItem in payload {
if let user = payloadItem["user"] {
print("user: %#", user);
}
}
user is not an array but dictionary. Try the following, it should work:
if let user = (payload["user"] as? [String:AnyObject]) {
print("\(user)")
}
this post follows an old post where some people helped me for a similar problem.
I currently developing an app which list user object by making an request to a webservice, which send a response in JSON in this format :
{
"objects": [
{
"id": "28",
"title": "test",
"price": "56 €",
"description": "kiki",
"addedDate": "11-07-2015",
"user_id": "1",
"user_name": "CANOVAS",
"user_zipCode": "69330",
"category_id": "1",
"category_label": "VEHICULES",
"subcategory_id": "1",
"subcategory_label": "Voitures",
"picture": "",
"bdd": {},
"picture_url": "http://jdl-barreme-orange.dyndns.org/WEBSERVICE/pictures/test.JPG"
},
{
"id": "27",
"title": "ferrari",
"price": "55 €",
"description": "rouge jantes",
"addedDate": "11-07-2015",
"user_id": "1",
"user_name": "CANOVAS",
"user_zipCode": "69330",
"category_id": "1",
"category_label": "VEHICULES",
"subcategory_id": "1",
"subcategory_label": "Voitures",
"picture": "",
"bdd": {},
"picture_url": "http://jdl-barreme-orange.dyndns.org/WEBSERVICE/pictures/ferrari.JPG"
}
}
I search a method to retrieve for each dictionary the value title and price and put them in a tableView.
Code I used (tableviewcontroller) :
if let jsonArray = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [[String:AnyObject]] {
for dict in jsonArray {
if let title = dict["title"] as? String {
println(title)
}
}
}
But it doesn't work, I put a breakpoint, and Xcode stop to interpret here :
for dict in jsonArray
Thanks for your help.
This example JSON is not valid: it lacks a ] before the last }.
But I guess this is just a pasting typo and the JSON you're using is properly formatted, so your problem is that you need to first access the objects key of your dictionary.
This key holds a value of an array of dictionaries, so we're using it as a typecast:
if let json = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [String:AnyObject] {
if let objects = json["objects"] as? [[String:AnyObject]] {
for dict in objects {
if let title = dict["title"] as? String {
println(title)
}
}
}
}
First we cast the result of NSJSONSerialization.JSONObjectWithData as the dictionary: [String:AnyObject], then we access the value for the objects key, then we cast this value as an array of dictionaries: [[String:AnyObject]].
Remember, with JSON format, dictionaries are formatted with {} and arrays are formatted with [].
Your example is {key:[{},{}]} so it's a dictionary holding an array of dictionaries.
Update for Swift 2.0
if let json = try? NSJSONSerialization.JSONObjectWithData(urlData!, options: []) as? [String:AnyObject] {
if let objects = json?["objects"] as? [[String:AnyObject]] {
for dict in objects {
if let title = dict["title"] as? String {
print(title)
}
}
}
}
Try this :
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary
var DataFromJSon = jsonResult["objects"] as! NSArray
for one in DataFromJSon {
var title = one["title"] as! String
println(title)
}
I tried to get the value of "seed" from json response. But i am getting nil.
Json Response:
{
"response": {
"params": {
"rows": "20",
"defType": "abc",
"seed": "381786611"
}
}
}
Swift Parsing:
if let responseHeader:AnyObject = object?["response"] as? NSDictionary {
if let t = (responseHeader["params"] as? NSDictionary){
let t1 = t["seed"] as? String
println("result is \(t1)") // This returns nil
}
}
Json Parsing
func processJsonToDictionary(object:AnyObject?) -> AnyObject?{
if object != nil {
if let data: AnyObject = object {
var parseError: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(object as NSData!, options: NSJSONReadingOptions.MutableContainers, error: &parseError) as? NSDictionary
if(parseError != nil){
return parseError
}
else{
return jsonResult
}
}
}
return nil
}
I am not able to get the value of t1. it always returns nil.
How can i get the value.
Also, I put a breakpoint and tried to print the value of t1. But the Xcode Keeps crashing. Why?
I think the major problem here is only accessing a JSON object in swift.
var error: NSError?
let jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as NSDictionary
let resp = jsonDict["response"] as? NSDictionary
let params = resp?["params"]?["seed"]
let seed = params!! as NSString
This is just to show you how a JSON object is accessed in swift. You can ofcourse change it according to your needs to remove unwanted Optional Chaining.
For easy JSON manipulation in Swift you could try this little library. It seems pretty easy and you could do this:
var dictionary: [String: AnyObject]!
if let json = NKJSON.parse(yourNSDataObject) {
dictionary <> json[NKJSON.rootKey]
}
First confirm that the response which you are getting is in json format or in string format.
For json parsing you can use swifty json pod