This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have an NSString that is storing a JSON array in the form of a NSString. The NSString called colorArray has the value of:
[{ "color":"Red" },{ "color":"Blue" },{ "color":"Yellow"}];
I also have a tableview that I would like to import the array into in order to populate the table. The table works if I load the tableData into an array like below, but I can't figure out how to convert the NSString into an array that can be used to populate the tableData like shown below...
Anyone have ideas? Thanks much!
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialize table data
tableData = [NSArray arrayWithObjects:#"Red", #"Blue", #"Yellow", nil];
}
// Your JSON data:
NSString *colorArray = #"[{ \"color\":\"Red\" },{ \"color\":\"Blue\" },{ \"color\":\"Yellow\"}]";
NSLog(#"colorArray=%#", colorArray);
// Convert to JSON object:
NSArray *jsonObject = [NSJSONSerialization JSONObjectWithData:[colorArray dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:NULL];
NSLog(#"jsonObject=%#", jsonObject);
// Extract "color" values:
NSArray *tableData = [jsonObject valueForKey:#"color"];
NSLog(#"tableData=%#", tableData);
Output:
colorArray=[{ "color":"Red" },{ "color":"Blue" },{ "color":"Yellow"}]
jsonObject=(
{
color = Red;
},
{
color = Blue;
},
{
color = Yellow;
}
)
tableData=(
Red,
Blue,
Yellow
)
The last step uses the special feature of -[NSArray valueForKey:]
that returns an array containing the results of invoking valueForKey: using the key on each of the array's objects.
Try
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *jsonString = ...//String representation of json
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
//colors is a NSArray property used as dataSource of TableView
self.colors = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:nil];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.colors count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *color = self.colors[indexPath.row];
cell.textLabel.text = color[#"color"];
return cell;
}
NSData * data = [colorArray dataUsingEncoding:NSUTF8StringEncoding]
NSDictionary *JSON =
[NSJSONSerialization JSONObjectWithData: data
options: NSJSONReadingMutableContainers
error: &e];
NSArray *tableData = [JSON valueForKey:#"color"];
Hope this helps..
Assuming you are using ios 5 or higher, JSON serialization is built in:
NSArray *json = [NSJSONSerialization
JSONObjectWithData:[string dataUsingEncoding:NSUTF8StringEncoding]
options:kNilOptions
error:&error];
Prior to ios5, you can use SBJSON to achieve the same:
NSArray *jsonObjects = [jsonParser objectWithString:string error:&error];
You just need to parse your tring in this way :
NSString *jsonString = #"[{\"color\":\"Red\" },{\"color\":\"Blue\" },{\"color\":\"Yellow\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
after this you have an array of dictionay to get all the values you have to do loop the array and read each dictionary
NSMutableArray *colorsArray = [NSMutableArray arrayWithCapacity:[jsonArray count]];
for (NSDictionary *colorDictionary in jsonArray) {
NSString *colorString = [colorDictionary objectForKey:#"color"];
[colorsArray addObject:colorString];
}
Now colorsArray is NSMutableArray like this :
[NSMutableArray arrayWithObjects:#"Red", #"Blue", #"Yellow", nil];
If your data in coming from a webservice:
NSArray *tableData = [[NSJSONSerialization JSONObjectWithData:request.responseData options: NSJSONReadingMutableContainers error: &error] objectForKey:"yourKeyForColorArray"];
Related
I have used the below code to convert the JSON data(from SOAP service) to NSDictionary.
-(void)retriveFromSYSoapTool:(NSMutableArray *)_data{
NSLog(#"data: %#",_data);
NSArray *value = [_data valueForKey:#"GetDemoDataResult"];
NSError *error;
NSData *objData = [value[0] dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"%#",json);
}
Output
2017-04-04 13:03:51.085 SoapService[18444:588594] (
{
firstName = "1 Jhon";
lastName = Macay;
},
{
firstName = "2 William";
lastName = Proter;
},
{
firstName = "3 Joe";
lastName = Root;
},
{
firstName = "4 Brendon";
lastName = Haejoy;
},
{
firstName = "5 Jhon";
lastName = Snow;
},
{
firstName = "6 Theon";
lastName = Greyjoy;
}
)
Do I need to convert this to any other? or how could I bind the above output in UITableView?
To work with table view you need array
Checkout this simple table view tutorial
It should be like this
Declare jsonArray in your .h file
#property (strong, nonatomic) NSMutableArray *jsonArray;
Add below line viewDidLoad
self.jsonArray = [[NSMutableArray alloc]init];
-(void)retriveFromSYSoapTool:(NSMutableArray *)_data{
NSLog(#"data: %#",_data);
NSArray *value = [_data valueForKey:#"GetDemoDataResult"];
NSError *error;
NSData *objData = [value[0] dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"%#",son);
[self.jsonArray addObject:[[json objectForKey:#"firstname"]stringByAppendingString:[json objectForKey:#"lastname"]];
[tableViewName reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.jsonArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [self.jsonArray objectAtIndex:indexPath.row];
return cell;
}
take one NSMutuableArray and add dictionary to this array like
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject: json];
//Than Reload Tableview
Note: Declare array Globally to access in your class
tableview display data like
cell.label.text = [[array objectAtIndex:indexPath.row]valueForKey:#"firstName"];
Store json data into Global Declare NSArray.
-(void)retriveFromSYSoapTool:(NSMutableArray *)_data{
NSLog(#"data: %#",_data);
NSArray *value = [_data valueForKey:#"GetDemoDataResult"];
NSError *error;
NSData *objData = [value[0] dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"%#",json);
DataArray = [NSArray arrayWithObjects:json, nil];
[tableView reloadData];
}
Here DataArray is Globally Declare NSArray Object;
Now Write UITableView DataSource Method.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return DataArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"jsoncell" forIndexPath:indexPath];
NSDictionary *dict = DataArray[indexPath.row];
NSString *output = [NSString stringWithFormat:#"%# %#",dict[#"firstName"],dict[#"lastName"]];
cell.textLabel.text = output;
return cell;
}
How send data to tableview in iOS with objective-C? I am trying to solve my problem very long time but result is not correct. My tableview is still empty. What I'm doing wrong? Below is my implementation file.
import "PlacesViewController.h"
#implementation PlacesViewController
#synthesize places;
- (void)viewDidLoad
{
[super viewDidLoad];
// Set this view controller object as the delegate and data source for the table view
self.listTableView.delegate = self;
self.listTableView.dataSource = self;
}
-(void)queryGooglePlaces
{
//Build the url string to send to Google
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=51.503186,-0.126446&radius=5000&types=food#|restaurant|bar&keyword=vegetarian&key=myOwnKEY"];
url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#", url);
//Formulate the string as a URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
dispatch_sync(dispatch_get_main_queue(), ^{
[self fetchedData:data];
});
});
}
-(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
self.places = [json objectForKey:#"results"];
//Write out the data to the console.
NSLog(#"Google Data: %#", json);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.places count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *tempDictionary= [self.places objectAtIndex:indexPath.row];
cell.textLabel.text = [tempDictionary objectForKey:#"name"];
return cell;
}
#end
Whenever you update the datasource, you need to call [self.tableView reloadData]
So it should be like this
-(void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
self.places = [json objectForKey:#"results"];
// NOTE - ADDED RELOAD
[self.tableView reloadData];
//Write out the data to the console.
NSLog(#"Google Data: %#", json);
}
For more information about reloadData see the answer
After you update the data source you should reload the table view.
self.places = [json objectForKey:#"results"];
[self.tableView reloadData];
I need to display the address in a tableview. How can i break the JSON and save the addresses in an NSArray.
The JSON is :
{
"Rank": 54,
"data": [
{
"number": 1,
"address": "x mandt "
},
{
"number": 2,
"address": "x mandt2 "
}
]
}
COde is:
NSDictionary *dic = (NSDictionary *) responseObject;
NSDictionary * dat = [dic objectForKey:#"data"];
NSArray *add =[dat objectForKey:#"address"];
The above code, doesn't retrieve and save all the address in the add array. How can i solve this?
assume that this is your serialization data
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:responseData options: NSJSONReadingMutableContainers error: &err];
// here I start your work
NSArray *infoDict=[jsonArray objectForKey:#"data"];
for (NSDictionary *tmp in infoDict)
{
NSMutableDictionary *temparr=[[NSMutableDictionary alloc]init];
[temparr setValue:[tmp objectForKey:#"number"] forKey:#"number"];
[temparr setValue:[tmp objectForKey:#"address"] forKey:#"address"];
[_tdataSource addObject:temparr];
}
[yourtableviewNAme reloadData];
here I add the Tableview DataSource and delegate method
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [self.tdataSource count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"resultCell";
yourtableviewCellName *cell = [self.yourtableName dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[yourtableviewCellName alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text=[[self.tdataSource objectAtIndex:indexPath.row]objectForKey:#"address"];
return cell;
}
I think you better just use the literal syntax for retrieving this. The way you retrieve is just fine. You probably just add some introspection:
NSDictionary *responseDict = (NSDictionary *) responseObject;
if (responseDict.count) {
NSArray *dataArray = responseDict[#"data"];
if (dataArray.count) {
// do whatever you want
}
}
You made a mistake when you retrieve the key word data, you will get an array after that but not a NSDictionary.
It should be:
NSArray *add =[dic objectForKey:#"data"];
Then if you want to have the address (I am considering address in 0'th index) then do this:
NSString *str = [[add objectAtIndex: 0] objectForKey:#"address"];
Edit:
Declare a class variable like:
#interface YourClassName (){
NSMutableArray *dataSource;
}
Populate the dataSource like:
dataSource =[dic objectForKey:#"data"];
Then In your cellForRowAtIndexPath method do this:
cell.textLabel.text = [[dataSource objectAtIndex:indexPath.row] objectForKey:#"address"];
I am considering you have single section in your tableview. Hope this helps.. :)
I have a JSON string (from PHP's json_encode() that looks like this:
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]
I want to parse this into some sort of data structure for my iPhone app. I guess the best thing for me would be to have an array of dictionaries, so the 0th element in the array is a dictionary with keys "id" => "1" and "name" => "Aaa".
I do not understand how the NSJSONSerialization stores the data though. Here is my code so far:
NSError *e = nil;
NSDictionary *JSON = [NSJSONSerialization
JSONObjectWithData: data
options: NSJSONReadingMutableContainers
error: &e];
This is just something I saw as an example on another website. I have been trying to get a read on the JSON object by printing out the number of elements and things like that, but I am always getting EXC_BAD_ACCESS.
How do I use NSJSONSerialization to parse the JSON above, and turn it into the data structure I mentioned?
Your root json object is not a dictionary but an array:
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]
This might give you a clear picture of how to handle it:
NSError *e = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
if (!jsonArray) {
NSLog(#"Error parsing JSON: %#", e);
} else {
for(NSDictionary *item in jsonArray) {
NSLog(#"Item: %#", item);
}
}
This is my code for checking if the received json is an array or dictionary:
NSError *jsonError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];
if ([jsonObject isKindOfClass:[NSArray class]]) {
NSLog(#"its an array!");
NSArray *jsonArray = (NSArray *)jsonObject;
NSLog(#"jsonArray - %#",jsonArray);
}
else {
NSLog(#"its probably a dictionary");
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
NSLog(#"jsonDictionary - %#",jsonDictionary);
}
I have tried this for options:kNilOptions and NSJSONReadingMutableContainers and works correctly for both.
Obviously, the actual code cannot be this way where I create the NSArray or NSDictionary pointer within the if-else block.
It works for me. Your data object is probably nil and, as rckoenes noted, the root object should be a (mutable) array. See this code:
NSString *jsonString = #"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e = nil;
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(#"%#", json);
(I had to escape the quotes in the JSON string with backslashes.)
Your code seems fine except the result is an NSArray, not an NSDictionary, here is an example:
The first two lines just creates a data object with the JSON, the same as you would get reading it from the net.
NSString *jsonString = #"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e;
NSMutableArray *jsonList = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(#"jsonList: %#", jsonList);
NSLog contents (a list of dictionaries):
jsonList: (
{
id = 1;
name = Aaa;
},
{
id = 2;
name = Bbb;
}
)
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]
In above JSON data, you are showing that we have an array contaning the number of dictionaries.
You need to use this code for parsing it:
NSError *e = nil;
NSArray *JSONarray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
for(int i=0;i<[JSONarray count];i++)
{
NSLog(#"%#",[[JSONarray objectAtIndex:i]objectForKey:#"id"]);
NSLog(#"%#",[[JSONarray objectAtIndex:i]objectForKey:#"name"]);
}
For swift 3/3+
//Pass The response data & get the Array
let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]
print(jsonData)
// considering we are going to get array of dictionary from url
for item in jsonData {
let dictInfo = item as! [String:AnyObject]
print(dictInfo["id"])
print(dictInfo["name"])
}
The following code fetches a JSON object from a webserver, and parses it to an NSDictionary. I have used the openweathermap API that returns a simple JSON response for this example. For keeping it simple, this code uses synchronous requests.
NSString *urlString = #"http://api.openweathermap.org/data/2.5/weather?q=London,uk"; // The Openweathermap JSON responder
NSURL *url = [[NSURL alloc]initWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response;
NSData *GETReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:GETReply options:NSJSONReadingMutableLeaves|| NSJSONReadingMutableContainers error:nil];
Nslog(#"%#",res);
#rckoenes already showed you how to correctly get your data from the JSON string.
To the question you asked: EXC_BAD_ACCESS almost always comes when you try to access an object after it has been [auto-]released. This is not specific to JSON [de-]serialization but, rather, just has to do with you getting an object and then accessing it after it's been released. The fact that it came via JSON doesn't matter.
There are many-many pages describing how to debug this -- you want to Google (or SO) obj-c zombie objects and, in particular, NSZombieEnabled, which will prove invaluable to you in helping determine the source of your zombie objects. ("Zombie" is what it's called when you release an object but keep a pointer to it and try to reference it later.)
Swift 2.0 on Xcode 7 (Beta) with do/try/catch block:
// MARK: NSURLConnectionDataDelegate
func connectionDidFinishLoading(connection:NSURLConnection) {
do {
if let response:NSDictionary = try NSJSONSerialization.JSONObjectWithData(receivedData, options:NSJSONReadingOptions.MutableContainers) as? Dictionary<String, AnyObject> {
print(response)
} else {
print("Failed...")
}
} catch let serializationError as NSError {
print(serializationError)
}
}
NOTE: For Swift 3.
Your JSON String is returning Array instead of Dictionary. Please try out the following:
//Your JSON String to be parsed
let jsonString = "[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
//Converting Json String to NSData
let data = jsonString.data(using: .utf8)
do {
//Parsing data & get the Array
let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]
//Print the whole array object
print(jsonData)
//Get the first object of the Array
let firstPerson = jsonData[0] as! [String:Any]
//Looping the (key,value) of first object
for (key, value) in firstPerson {
//Print the (key,value)
print("\(key) - \(value) ")
}
} catch let error as NSError {
//Print the error
print(error)
}
#import "homeViewController.h"
#import "detailViewController.h"
#interface homeViewController ()
#end
#implementation homeViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.frame = CGRectMake(0, 20, 320, 548);
self.title=#"Jason Assignment";
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self clientServerCommunication];
}
-(void)clientServerCommunication
{
NSURL *url = [NSURL URLWithString:#"http://182.72.122.106/iphonetest/getTheData.php"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:req delegate:self];
if (connection)
{
webData = [[NSMutableData alloc]init];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
/*Third party API
NSString *respStr = [[NSString alloc]initWithData:webData encoding:NSUTF8StringEncoding];
SBJsonParser *objSBJson = [[SBJsonParser alloc]init];
NSDictionary *responseDict = [objSBJson objectWithString:respStr]; */
resultArray = [[NSArray alloc]initWithArray:[responseDict valueForKey:#"result"]];
NSLog(#"resultArray: %#",resultArray);
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return [resultArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [[resultArray objectAtIndex:indexPath.row] valueForKey:#"name"];
cell.detailTextLabel.text = [[resultArray objectAtIndex:indexPath.row] valueForKey:#"designation"];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[resultArray objectAtIndex:indexPath.row] valueForKey:#"image"]]];
cell.imageview.image = [UIImage imageWithData:imageData];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Table view delegate
// In a xib-based application, navigation from a table can be handled in -tableView:didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here, for example:
//Create the next view controller.
detailViewController *detailViewController1 = [[detailViewController alloc]initWithNibName:#"detailViewController" bundle:nil];
//detailViewController *detailViewController = [[detailViewController alloc] initWithNibName:#"detailViewController" bundle:nil];
// Pass the selected object to the new view controller.
// Push the view controller.
detailViewController1.nextDict = [[NSDictionary alloc]initWithDictionary:[resultArray objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:detailViewController1 animated:YES];
// Pass the selected object to the new view controller.
// Push the view controller.
// [self.navigationController pushViewController:detailViewController animated:YES];
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
empName.text=[nextDict valueForKey:#"name"];
deptlbl.text=[nextDict valueForKey:#"department"];
designationLbl.text=[nextDict valueForKey:#"designation"];
idLbl.text=[nextDict valueForKey:#"id"];
salaryLbl.text=[nextDict valueForKey:#"salary"];
NSString *ImageURL = [nextDict valueForKey:#"image"];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
image.image = [UIImage imageWithData:imageData];
}
The issue seems to be with autorelease of objects. NSJSONSerialization JSONObjectWithData is obviously creating some autoreleased objects and passing it back to you. If you try to take that on to a different thread, it will not work since it cannot be deallocated on a different thread.
Trick might be to try doing a mutable copy of that dictionary or array and use it.
NSError *e = nil;
id jsonObject = [NSJSONSerialization
JSONObjectWithData: data
options: NSJSONReadingMutableContainers
error: &e] mutableCopy];
Treating a NSDictionary as NSArray will not result in Bad access exception but instead will probably crash when a method call is made.
Also, may be the options do not really matter here but it is better to give NSJSONReadingMutableContainers | NSJSONReadingMutableContainers |
NSJSONReadingAllowFragments but even if they are autoreleased objects it may not solve this issue.
bad example, should be something like this
{"id":1, "name":"something as name"}
number and string are mixed.
I have a JSON string (from PHP's json_encode() that looks like this:
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]
I want to parse this into some sort of data structure for my iPhone app. I guess the best thing for me would be to have an array of dictionaries, so the 0th element in the array is a dictionary with keys "id" => "1" and "name" => "Aaa".
I do not understand how the NSJSONSerialization stores the data though. Here is my code so far:
NSError *e = nil;
NSDictionary *JSON = [NSJSONSerialization
JSONObjectWithData: data
options: NSJSONReadingMutableContainers
error: &e];
This is just something I saw as an example on another website. I have been trying to get a read on the JSON object by printing out the number of elements and things like that, but I am always getting EXC_BAD_ACCESS.
How do I use NSJSONSerialization to parse the JSON above, and turn it into the data structure I mentioned?
Your root json object is not a dictionary but an array:
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]
This might give you a clear picture of how to handle it:
NSError *e = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
if (!jsonArray) {
NSLog(#"Error parsing JSON: %#", e);
} else {
for(NSDictionary *item in jsonArray) {
NSLog(#"Item: %#", item);
}
}
This is my code for checking if the received json is an array or dictionary:
NSError *jsonError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];
if ([jsonObject isKindOfClass:[NSArray class]]) {
NSLog(#"its an array!");
NSArray *jsonArray = (NSArray *)jsonObject;
NSLog(#"jsonArray - %#",jsonArray);
}
else {
NSLog(#"its probably a dictionary");
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
NSLog(#"jsonDictionary - %#",jsonDictionary);
}
I have tried this for options:kNilOptions and NSJSONReadingMutableContainers and works correctly for both.
Obviously, the actual code cannot be this way where I create the NSArray or NSDictionary pointer within the if-else block.
It works for me. Your data object is probably nil and, as rckoenes noted, the root object should be a (mutable) array. See this code:
NSString *jsonString = #"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e = nil;
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(#"%#", json);
(I had to escape the quotes in the JSON string with backslashes.)
Your code seems fine except the result is an NSArray, not an NSDictionary, here is an example:
The first two lines just creates a data object with the JSON, the same as you would get reading it from the net.
NSString *jsonString = #"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e;
NSMutableArray *jsonList = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(#"jsonList: %#", jsonList);
NSLog contents (a list of dictionaries):
jsonList: (
{
id = 1;
name = Aaa;
},
{
id = 2;
name = Bbb;
}
)
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]
In above JSON data, you are showing that we have an array contaning the number of dictionaries.
You need to use this code for parsing it:
NSError *e = nil;
NSArray *JSONarray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
for(int i=0;i<[JSONarray count];i++)
{
NSLog(#"%#",[[JSONarray objectAtIndex:i]objectForKey:#"id"]);
NSLog(#"%#",[[JSONarray objectAtIndex:i]objectForKey:#"name"]);
}
For swift 3/3+
//Pass The response data & get the Array
let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]
print(jsonData)
// considering we are going to get array of dictionary from url
for item in jsonData {
let dictInfo = item as! [String:AnyObject]
print(dictInfo["id"])
print(dictInfo["name"])
}
The following code fetches a JSON object from a webserver, and parses it to an NSDictionary. I have used the openweathermap API that returns a simple JSON response for this example. For keeping it simple, this code uses synchronous requests.
NSString *urlString = #"http://api.openweathermap.org/data/2.5/weather?q=London,uk"; // The Openweathermap JSON responder
NSURL *url = [[NSURL alloc]initWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response;
NSData *GETReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:GETReply options:NSJSONReadingMutableLeaves|| NSJSONReadingMutableContainers error:nil];
Nslog(#"%#",res);
#rckoenes already showed you how to correctly get your data from the JSON string.
To the question you asked: EXC_BAD_ACCESS almost always comes when you try to access an object after it has been [auto-]released. This is not specific to JSON [de-]serialization but, rather, just has to do with you getting an object and then accessing it after it's been released. The fact that it came via JSON doesn't matter.
There are many-many pages describing how to debug this -- you want to Google (or SO) obj-c zombie objects and, in particular, NSZombieEnabled, which will prove invaluable to you in helping determine the source of your zombie objects. ("Zombie" is what it's called when you release an object but keep a pointer to it and try to reference it later.)
Swift 2.0 on Xcode 7 (Beta) with do/try/catch block:
// MARK: NSURLConnectionDataDelegate
func connectionDidFinishLoading(connection:NSURLConnection) {
do {
if let response:NSDictionary = try NSJSONSerialization.JSONObjectWithData(receivedData, options:NSJSONReadingOptions.MutableContainers) as? Dictionary<String, AnyObject> {
print(response)
} else {
print("Failed...")
}
} catch let serializationError as NSError {
print(serializationError)
}
}
NOTE: For Swift 3.
Your JSON String is returning Array instead of Dictionary. Please try out the following:
//Your JSON String to be parsed
let jsonString = "[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
//Converting Json String to NSData
let data = jsonString.data(using: .utf8)
do {
//Parsing data & get the Array
let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]
//Print the whole array object
print(jsonData)
//Get the first object of the Array
let firstPerson = jsonData[0] as! [String:Any]
//Looping the (key,value) of first object
for (key, value) in firstPerson {
//Print the (key,value)
print("\(key) - \(value) ")
}
} catch let error as NSError {
//Print the error
print(error)
}
#import "homeViewController.h"
#import "detailViewController.h"
#interface homeViewController ()
#end
#implementation homeViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.frame = CGRectMake(0, 20, 320, 548);
self.title=#"Jason Assignment";
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self clientServerCommunication];
}
-(void)clientServerCommunication
{
NSURL *url = [NSURL URLWithString:#"http://182.72.122.106/iphonetest/getTheData.php"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:req delegate:self];
if (connection)
{
webData = [[NSMutableData alloc]init];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
/*Third party API
NSString *respStr = [[NSString alloc]initWithData:webData encoding:NSUTF8StringEncoding];
SBJsonParser *objSBJson = [[SBJsonParser alloc]init];
NSDictionary *responseDict = [objSBJson objectWithString:respStr]; */
resultArray = [[NSArray alloc]initWithArray:[responseDict valueForKey:#"result"]];
NSLog(#"resultArray: %#",resultArray);
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
return [resultArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [[resultArray objectAtIndex:indexPath.row] valueForKey:#"name"];
cell.detailTextLabel.text = [[resultArray objectAtIndex:indexPath.row] valueForKey:#"designation"];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[resultArray objectAtIndex:indexPath.row] valueForKey:#"image"]]];
cell.imageview.image = [UIImage imageWithData:imageData];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Table view delegate
// In a xib-based application, navigation from a table can be handled in -tableView:didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here, for example:
//Create the next view controller.
detailViewController *detailViewController1 = [[detailViewController alloc]initWithNibName:#"detailViewController" bundle:nil];
//detailViewController *detailViewController = [[detailViewController alloc] initWithNibName:#"detailViewController" bundle:nil];
// Pass the selected object to the new view controller.
// Push the view controller.
detailViewController1.nextDict = [[NSDictionary alloc]initWithDictionary:[resultArray objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:detailViewController1 animated:YES];
// Pass the selected object to the new view controller.
// Push the view controller.
// [self.navigationController pushViewController:detailViewController animated:YES];
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
empName.text=[nextDict valueForKey:#"name"];
deptlbl.text=[nextDict valueForKey:#"department"];
designationLbl.text=[nextDict valueForKey:#"designation"];
idLbl.text=[nextDict valueForKey:#"id"];
salaryLbl.text=[nextDict valueForKey:#"salary"];
NSString *ImageURL = [nextDict valueForKey:#"image"];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
image.image = [UIImage imageWithData:imageData];
}
The issue seems to be with autorelease of objects. NSJSONSerialization JSONObjectWithData is obviously creating some autoreleased objects and passing it back to you. If you try to take that on to a different thread, it will not work since it cannot be deallocated on a different thread.
Trick might be to try doing a mutable copy of that dictionary or array and use it.
NSError *e = nil;
id jsonObject = [NSJSONSerialization
JSONObjectWithData: data
options: NSJSONReadingMutableContainers
error: &e] mutableCopy];
Treating a NSDictionary as NSArray will not result in Bad access exception but instead will probably crash when a method call is made.
Also, may be the options do not really matter here but it is better to give NSJSONReadingMutableContainers | NSJSONReadingMutableContainers |
NSJSONReadingAllowFragments but even if they are autoreleased objects it may not solve this issue.
bad example, should be something like this
{"id":1, "name":"something as name"}
number and string are mixed.