I have tried this a few times and I still don't get how to go into a JSON feed and retrieve what I need to grab.
The feed looks like this, in my code i'm trying to pull out all the titles. I dont know how to get down into the Json Feed.
- (void)viewDidLoad
{
[super viewDidLoad];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:#"http://api.storageroomapp.com/accounts/511a4f810f66026b640007b8/collections/511a51580f66023bff000ce9/entries.json?auth_token=Zty6nKsFyqpy7Yp5DP1L&preview_api=1"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
// Do any additional setup after loading the view from its nib.
}
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
data = [[NSMutableData alloc] init];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData{
[data appendData:theData];
}
-(void)connectionDidFinishLoading:(NSURLConnection *) connection{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
news = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
[mainTableView reloadData];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"The data could not be downloaded - please make sure you're connected to either 3G or Wi-FI" delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
-(int)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [news count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MainCell"];
cell.textLabel.text = [[news objectAtIndex:indexPath.row] objectForKey:#"title"];
}
return cell;
}
and In my .H i have NSArray *news; and NSMutableData *data.
Any help would be great, could you please explain your self clearly as I'm a total newbie to this language.
Looking at the logic that you have in your code and the sample JSON that you posted, it doesn't look like your array is being populated with what you would want.
Initially, the JSON is in the form of a dictionary (hence the curly braces in the image you provided). Therefore, you should adjust your initial parsing of the JSON to something like so:
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
From here, you can receive a key from the dictionary. The one you'd be looking for is "array", which also actually is a dictionary despite its name.
NSDictionary *arrayDictionary = dictionary[#"array"];
Moving right along, you can finally access the "resources" array that you are looking for, and you can store that within the instance variable that you created in your .h file.
news = arrayDictionary[#"resources"];
Now, in the cellForRowAtIndexPath method you can access various elements of this array based on the index path row that is provided to you.
NSDictionary *newsItem = news[[indexPath row]];
Finally, you can access various properties like the titles from that news item, and set the text label's text.
NSString *title = newsItem[#"title"];
[[cell textLabel] setText:title];
Related
This question already has answers here:
json parsing+iphone
(4 answers)
Closed 9 years ago.
I have to retrieve data from web-service and store in to table-view.
I have one framework but that cant work for me that is here
HERE PROBLEM IS USING THAT CAN'T ALLOWED TO CREATE CREATE OBJECT OF IT.
Thank you
You don't need to create the object of json.h file. You just need to import json.h file and then use it by [responseString JSONValue].
check this code
#interface videoViewController ()
{
NSMutableData *webData;
NSURLConnection *connection;
NSMutableArray *array;
NSMutableArray *array2;
}
- (void)viewDidLoad
{
[super viewDidLoad];
array=[[NSMutableArray alloc]init];
array2=[[NSMutableArray alloc]init];
NSURL *url=[NSURL URLWithString:#"http://localhost/videosphp/videoname2.php"];
NSURLRequest *request=[NSURLRequest requestWithURL:url];
connection=[NSURLConnection connectionWithRequest:request 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)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Unable to connect internet. Please check your internet connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//use NSDictionary if the data in dictionary
NSArray *allDataArray=[NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
for (NSDictionary *diction in allDataArray)
{
NSString *videoname=[diction objectForKey:#"videoname"];
[array addObject:videoname];
}
[[self tableview]reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"Cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellAccessoryDisclosureIndicator reuseIdentifier:CellIdentifier];
}
cell.textLabel.text=[array objectAtIndex:indexPath.row];
return cell;
}
Im trying to get deep into a nested JSon Array, i have successfully done it for the level above but I cant work out how to get any deeper.
I need to log the image #url I have attached a screen show to show where i need it to go.
Thanks :)
- (void)viewDidLoad
{
[super viewDidLoad];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = [NSURL URLWithString:#"http://api.storageroomapp.com/accounts/511a4f810f66026b640007b8/collections/511a51580f66023bff000ce9/entries.json?auth_token=Zty6nKsFyqpy7Yp5DP1L&preview_api=1"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
-(void)connectionDidFinishLoading:(NSURLConnection *) connection{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
NSDictionary *arrayDictionary = dictionary[#"array"];
news = arrayDictionary[#"resources"];
[tableView reloadData];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:#"Error" message:#"The data could not be downloaded - please make sure you're connected to either 3G or Wi-FI" delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
-(int)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [news count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *newsItem = news[[indexPath row]];
NSString *title = newsItem[#"title"];
NSString *date = newsItem[#"date"];
NSString *thumb = newsItem[#"tablethumb"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MainCell"];
[[cell textLabel] setText:title];
[[cell detailTextLabel] setText:date];
if((NSNull *)thumb == [NSNull null]){
NSLog(#"no image");
} else{
NSLog(# "image = %#", thumb);
}
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
For traversing nested objects you could use valueForKeyPath method and use the dot syntax to drill down the hieararchy.
Something like this would fetch the url value from your newsItem dictionary:
NSDictionary *newsItem = news[[indexPath row]];
NSString *thumbUrl = [newsItem valueForKeyPath:#"tablethumb.url"];
PS. If you really have the properties prefixed by # then you might get into trouble by using valueForKeyPath since # is a special token used as an operator. In this case you could do something like this instead:
NSDictionary *newsItem = news[[indexPath row]];
id tablethumb = [newsItem objectForKey:#"tablethumb"];
NSString *thumbUrl = #"";
// Check if not null and access the #url
if (tablethumb != [NSNull null])
thumbUrl = tablethumb[#"#url"];
Try to access value from dictionary like this,
NSLog(#"URL: %#",[newsItem objectForKey:#"#url"]);
I am trying to load json into a uitableview. I have worked with json before but never used it with a tableview. I keep getting this error: -[__NSCFNumber count]: unrecognized selector sent to instance. I'm pretty sure it is because in the numberOfRowsInSection method im returning the count of the array. Please let me know how to fix this or if I am missing something and not seeing it.
Here is he code:
.h file
#interface HistoryViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
NSArray *jsonData;
NSMutableData *responseData;
}
.m file
- (void)viewDidLoad
{
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"Json url"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self ];
[super viewDidLoad];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Connection failed: %#", [error description]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *dictionary = [responseString JSONValue];
NSArray *response = [dictionary objectForKey:#"name"];
jsonData = [[NSArray alloc] initWithArray:response];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return jsonData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
cell.textLabel.text = [jsonData objectAtIndex:indexPath.row];
return cell;
}
All right, I notice that your array is never initialized until the connectionDidFinishLoading method is run. The delegate methods for your data table are likely running before connectionDidFinishLoading, so you should initialize your jsonData array in viewDidLoad instead of connectionDidFinishLoading.
You can keep your connectionDidFinishLoading calls the same, but make sure you call reloadData on your data table at the end of the connectionDidFinishLoading method to fill out your data table with the downloaded data.
atm i can successfully loading data from a WFC, read the json and put it on the right objects.
But my problem comes when i need to show a table with this data, cuz i don't know where to play the method or when should i call it. Atm looks like the table is created and after that i get the data from the web. Should i reload the table or can i get the info before the class calls cellForRowAtIndexPath: ?
Is there a way to make a connection synchronic and not synchronic? because in this case, if i cant get the list of eventos form wfc its has not point showing a table. So
Thx in advance!
my code:
-(id)init{
//call superclass designated inizialzer
self= [super initWithStyle:UITableViewStyleGrouped];
if(self){
[[self navigationItem] setTitle:#"Eventos"];
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://xxx.xxx.xxx.xxx/..."]];
[[[NSURLConnection alloc] initWithRequest:request delegate:self]autorelease];
}
return self;
}
about connection:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// label.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
NSDictionary *luckyNumbers = [json objectWithString:responseString error:&error];
[responseString release];
if (luckyNumbers == nil)
// label.text = [NSString stringWithFormat:#"JSON parsing failed: %#", [error localizedDescription]];
[luckyNumbers release];
else {
for (NSDictionary *object in [luckyNumbers objectForKey:#"EResult"]) {
Evento *e=[[Evento alloc] init];
e.nombre= [object objectForKey:#"nombre"];
e._id= (int)[object objectForKey:#"id"];
e.fecha= [object objectForKey:#"fecha"];
[[EventoStore defaultStore]addEvento:e];
[e release];
}
}
}
about the table it self:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [[[EventoStore defaultStore] allEventos]count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//check for reusable cell first and use it
UITableViewCell *cell= [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
//if there is no reusable cell, we create one
if(!cell){
cell= [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:#"UITableViewCell"]autorelease];
}
Evento *e=[[[EventoStore defaultStore] allEventos] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:[e nombre]];
return cell;
}
-(void)tableView:(UITableView *) aTableView didSelectRowAtIndexPath:(NSIndexPath *) indexPax{
LotesViewController *loteViewController= [[[LotesViewController alloc]init]autorelease];
NSArray *eventos=[[EventoStore defaultStore]allEventos];
[loteViewController setEvento: [eventos objectAtIndex:[indexPax row]]];
[[self navigationController]pushViewController:loteViewController animated:YES];
}
you should reload the table after getting the data. you can show the activity indicator on the table till you get the data and once you get the data, you can remove the activity indicator and reload the table. this way you can find the solution to your problem. No need to go for synchronous connection. Just add the activity indicator once the connection is satrted and remove it when data comes.
I am trying to add Loading data option in viewDidLoad() function before [self.tableview reloaddata]. I am not sure how to add it and is there a way to make the user know that there is data getting loaded.
I am parsing JSON file and the data gets loaded on 3G pretty slow, so its the better way to allow user to know that data is being loaded with loading option. Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Add the view controller's view to the window and display.
responseData = [[NSMutableData data] retain];
self.twitterArray = [NSMutableArray array];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://search.twitter.com/search.json?q=mobtuts&rpp=5"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
[super viewWillAppear:animated];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *results = [responseString JSONValue];
self.twitterArray = [results objectForKey:#"results"];
[self.tableView reloadData]; // How to add loading view before this statement
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.twitterArray count];
}
I'm not quite sure what you mean by "loading view" but i guess you mean an activity indicator or something else what should be presented while you are loading data.
make an ivar UIActivityIndicatorView *myLoadingView;
Init it in viewDidLoad
myLoadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
myLoadingView.hidesWhenStopped = YES;
[myLoadingView stopAnimating];
[self.view addSubView:myLoadingView];
show the view before you start your connection [myLoadingView startAnimating];
hide it again when the download was finished by stoping it in the delegate method connectionDidFinishLoading: after [self.tableView reloadData]; [myLoadingView stopAnimating];
release it in viewDidUnload [myLoadingView release];
Feel free to ask if you have questions or if i had misunderstood you.