I've been stuck on this problem for a while now. Basically i've been trying to pull a list of results from parse and then get information from a relational pointer.
I have got to the point where i can set the cells label to the title but it seems to have the same title for as many rows are returned.
I know i need to utilize the indexPath.row somewhere but i can't for the life of me think how.
Any help would be gratefully appreciated :)
//
// DEMOWatchedGamesTableViewController.m
// ShoutOutz
//
// Created by Craig Turner on 05/08/2014.
// Copyright (c) 2014 Roman Efimov. All rights reserved.
//
#import "DEMOWatchedGamesTableViewController.h"
#import <Parse/Parse.h>
#interface DEMOWatchedGamesTableViewController ()
#end
NSMutableArray *arrayGames;
#implementation DEMOWatchedGamesTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 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;
//PFUser *currentUser = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"watched_games"];
// Include the user data with each post
[query includeKey:#"game_id"];
[query findObjectsInBackgroundWithBlock:^(NSArray *postObjects, NSError *error)
{
if(!error){
NSLog(#"myArray: %#", postObjects);
self.myArray = postObjects;
[self.tableView reloadData];
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.myArray count];
//return 3;
}
- (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];
}
NSLog(#"Array: %#", self.myArray);
for (PFObject * postObject in self.myArray) {
[postObject fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error){
PFObject *postAuthor = [object objectForKey:#"game_id"];
NSLog(#"retrieved related Post Author: %#", postAuthor);
cell.textLabel.text = [postAuthor objectForKey:#"gameTitle"];
}];
}
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 - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Rememer that the tableView:cellForRowAtIndexPath: method is called once for every cell that needs to be displayed, and that's determined by the value you supply in the tableView:numberOfRowsInSection data source method, in this case - the size of your myArray array.
So based on that principle you dont need to go through your array for every iteration of the cellForRowAtIndexPath method. What's helpful with this method is that it lets you know which cell index it is going to create by supplying you the indexPath. So you can use this indexPath value supplied by the method as an index to then grab the appropriate instance in your array like so:
This is just an example based on your existing code:
- (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];
}
/**
Why are you printing the array? youll end up printing it as many times as there are instances
in your myArray array. You dont want to do that ;)
NSLog(#"Array: %#", self.myArray);
*/
//Using the indexpath's row value we can go ahead and grab that from your myArray array
PFObject * postObject = [self.myArray objectAtIndex:indexPath.row];
[postObject fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error){
PFObject *postAuthor = [object objectForKey:#"game_id"];
NSLog(#"retrieved related Post Author: %#", postAuthor);
cell.textLabel.text = [postAuthor objectForKey:#"gameTitle"];
}];
return cell;
}
Related
Hi when I do for loop to get all documents from a collection. I add the car object to the NSMutablearray and when I debug i can see that the objects are being added to the array but when i want it to display in the table and get the count of the array I call the [self.mycars count] to get the count but the count is nil and i cant get information from the cell.textLabel.text = vehicle.name; so what am i doing wrong.
#import "TableViewController.h"
#import "Car.h"
#import "Vehicle.h"
#interface TableViewController ()
#end
#implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 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.db = [FIRFirestore firestore];
self.myCars = [[NSMutableArray alloc] init];
[[[[self.db collectionWithPath:#"users"] documentWithPath:[FIRAuth auth].currentUser.uid]
collectionWithPath:#"cars"] getDocumentsWithCompletion:^(FIRQuerySnapshot *snapshot, NSError *error) {
if (error != nil) {
NSLog(#"Error getting documents: %#", error);
} else {
for (FIRDocumentSnapshot *document in snapshot.documents) {
NSLog(#"%# => %#", document.documentID, document.data);
Car *car = [[Car alloc] initWithCarName:[document valueForField:#"carname"] andCarStyle:[document valueForField:#"carstyle"]
andCarColour:[document valueForField:#"colour"] andCarYear:[document valueForField:#"caryear"]
andCarDoors:[document valueForField:#"doors"] andCarSeat:[document valueForField:#"seat"] andCarWheels:[document valueForField:#"wheels"]
andCarTankCapacity:[document valueForField:#"tankcapacity"] andCarHorsePower:[document valueForField:#"horsepower"] andCarModelName:[document valueForField:#"modelname"]];
NSLog(#"Car name:%#", car.name);
[self.myCars addObject:car];
}
}
}];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.myCars count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellidentifier" forIndexPath:indexPath];
// Configure the cell...'
Vehicle *vehicle = [self.myCars objectAtIndex:indexPath.row];
cell.textLabel.text = vehicle.name;
return cell;
}
#end
You need to reload data manually after changing/updating your datasource (self.myCars in this case) which mean you need to add [self.tableView reloadData]; after for loop. If it still is not working, you might want to check if self.myCars is initialized yet.
I am building a database style app using Parse in Xcode 5 and want to be able to order all the cells by date created. I also want to then be able to change this to alphabetical order when I click an option of a segmented control (by date order being the default). How do I do this?
My table view controller (.m):
#import "JKENotesListViewController.h"
#import "JKENotesViewController.h"
#import <Parse/Parse.h>
#interface JKENotesListViewController ()
#end
#implementation JKENotesListViewController
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithClassName:#"Post"];
self = [super initWithCoder:aDecoder];
if (self) {
// The className to query on
self.parseClassName = #"Post";
// Whether the built-in pull-to-refresh is enabled
self.pullToRefreshEnabled = YES;
// Whether the built-in pagination is enabled
self.paginationEnabled = YES;
// The number of objects to show per page
self.objectsPerPage = 15;
}
return self;
}
#pragma mark - UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(#"Current user: %#", currentUser.username);
}
else {
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self loadObjects];
}
#pragma mark - PFQueryTableViewController
// Override to customize the look of a cell representing an object. The default is to display
// a UITableViewCellStyleDefault style cell with the label being the textKey in the object,
// and the imageView being the imageKey in the object.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE, MMMM d yyyy"];
NSDate *date = [object createdAt];
// Configure the cell
cell.textLabel.text = [object objectForKey:#"title"];
cell.detailTextLabel.text = [dateFormatter stringFromDate:date];
cell.imageView.image = [UIImage imageNamed:#"bike-iconcell.png"];
return cell;
}
// Override to customize what kind of query to perform on the class. The default is to query for
// all objects ordered by createdAt descending.
- (PFQuery *)queryForTable {
// Create a query
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
// Follow relationship
if ([PFUser currentUser]) {
[query whereKey:#"author" equalTo:[PFUser currentUser]];
}
else {
// I added this so that when there is no currentUser, the query will not return any data
// Without this, when a user signs up and is logged in automatically, they briefly see a table with data
// before loadObjects is called and the table is refreshed.
// There are other ways to get an empty query, of course. With the below, I know that there
// is no such column with the value in the database.
[query whereKey:#"nonexistent" equalTo:#"doesn't exist"];
}
return query;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"showNote"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
JKENotesViewController *note = (JKENotesViewController *)segue.destinationViewController;
note.note = object;
}
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:#"showLogin" sender:self];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:animated];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Remove the row from data model
PFObject *object = [self.objects objectAtIndex:indexPath.row];
[object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[self refreshControl];
[tableView reloadData];
}];
}
}
#end
Many thanks in advance!
As a guideline, you have to sort you datasource (probably NS(Mutable)Array or NS(Mutable)Dictionary) as per your criteria and once the datasource is sorted out you need to call:
[yourTableView reloadData];
Later when you have to change the sort criteria to alphabetic order (may be through segmented control) sort data source in alphabetic order instead of date created, and don;t forget to reload your table again.
Below are some examples:
Sort in descending order
Sort using custom objects
I am new to iOS and I do not understand why when I click on my item in the cell it goes nowhere. No errors, no nothing. My segue ID is Cell. I Have a Button that works fine to add data, but I am trying to get to update the data if selected from the table.
Here is my .h and .m
DerbyProTableViewController.h:
#import <UIKit/UIKit.h>
#interface DerbyProTableViewController : UITableViewController
#property (strong) NSMutableArray *racerarray;
#end
DerbyProTableViewController.m:
#import "DerbyProTableViewController.h"
#import "DerbyProDetailViewController.h"
#interface DerbyProTableViewController ()
#end
#implementation DerbyProTableViewController
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Racer"];
self.racerarray = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[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
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.racerarray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *device = [self.racerarray objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%# %#", [device valueForKey:#"lastname"], [device valueForKey:#"firstname"]]];
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
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.racerarray objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.racerarray removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"updateracer"]){
NSManagedObject *selectedDevice = [self.racerarray objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
DerbyProDetailViewController *destinationViewController = segue.destinationViewController;
destinationViewController.derbyprodb = selectedDevice;
}
}
I'm going on just what I see in the code you pasted. I don't know what might have been setup in the storyboard but...
There's no delegate or datasource specified for the UITableView object. The UITableViewDelegate handles cell selection.
Once you've set up the delegate like this:
[self.tableview setDelegate:self];
You then need to implement:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"whateveryoursegueiscalled" sender:thecellyoutapped];
}
Have a read of Apple's tableview programming guide.
Chances are that you didn't add your class in the Identity inspector in your storyboard.
Select your view in the storyboard and click on identity ispector. Ensure that Class field is not empty
While I was surfing over the Internet I've found a lot of examples how to load array in the TableViewController, but none of them helped me!
Couldn't you help me to find what is wrong in my code ?
Thank you in advance!!!
#import "Images.h"
#import "AFNetworking.h"
#import "HTMLparser.h"
#interface Images ()
#end
#implementation Images
#synthesize data;
#synthesize textFromVC1;
#synthesize tableView;
#synthesize so2;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.data = [[NSMutableArray alloc]init];
NSError *error = nil;
NSString *so = [#"http://" stringByAppendingString: self.textFromVC1];
NSURL *url = [[NSURL alloc]initWithString:so];
NSString *str=[[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
HTMLParser *parser = [[HTMLParser alloc] initWithString:str error:&error];
if (error) {
NSLog(#"Error: %#", error);
[parser release];
parser = nil;
return;
}
HTMLNode * body = [parser body];
NSArray *inputs = [body findChildTags:#"img"];
for (HTMLNode *input in inputs) {
NSString *links = [input getAttributeNamed:#"src"];
NSString *so1 = [so stringByAppendingString: #"/"];
so2 = [so1 stringByAppendingString: links];
[self.data addObject:so2];
NSLog(#"%#", data);
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
{
}];
[operation start];
}
[self.tableView reloadData];
// 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;
}
- (void)viewDidUnload
{
[self setTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"LinkID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = [self.data objectAtIndex:indexPath.row];
[self.tableView reloadData];
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
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
- (void)dealloc {
[tableView release];
[super dealloc];
}
#end
well 1) numberOfSections is 0. to see something it should be one IIRC
think thats it but havent double checked
Assuming your data array is built up correctly, your mistake in is your numberOfSections methods. Currently, it returns 0, which tells the UITableView that there are currently no sections to be displayed… ever.
You can either return 1; there or remove the entire method altogether. The default implementation, which you inherit from UITableViewController, also returns 1 by default.
My advice would be to remove the method, as that keeps your own code cleaner. You can always implement it in a later stage, when you might actually need it.
I can parse data and see the output also but I am not able to display them in table view
when I call the view that contain JSON the application is crashed
This is my code:
In the first line of code we define a macro that gives us back a background queue – I like having a kBgQueue shortcut for that, so I can keep my code tighter.
In the second line of code we create a macro named kLatestKivaLoansURL which returns us an NSURL pointing to this URL http://api.kivaws.org/v1/loans/search.json?status=fundraising.
#define kBgQueue dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //1
#define kLatestKivaLoansURL [NSURL URLWithString:
#"http://api.kivaws.org/v1/loans/search.json?status=fundraising"] //2
#interface TeacherViewController ()
#end
#implementation TeacherViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
Defined kBGQueue as a macro which gives us a background queue?
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:kLatestKivaLoansURL];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
}
#synthesize latestLoans;
#synthesize arrayOfFighterName;
Will be called and the NSData instance will be passed to it. In our case the JSON file is relatively small so we’re going to do the parsing inside fetchedData: on the main thread. If you’re parsing large JSON feeds (which is often the case), be sure to do that in the background.
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
latestLoans = [json objectForKey:#"loans"]; //2
arrayOfFighterName=[[NSMutableArray alloc] init];
//NSLog(#"loans: %#", latestLoans); //3
for( int i = 0; i<[latestLoans count]; i++){
// NSLog(#"%#", [matchListArray objectAtIndex:i]);
arrayOfFighterName[i]=[[latestLoans objectAtIndex:i] objectForKey:#"name"];
// NSLog(#"%#", [arrayOfFighterName objectAtIndex:i]);
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
latestLoans = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
Displaying the result in table view
but unfortunately the result does not display and the app is crashed
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Return the number of rows in the section.
return [arrayOfFighterName count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"TeacherCell"];
cell.textLabel.text = [arrayOfFighterName objectAtIndex:indexPath.row];
return cell;
// NSLog(#"viewDidLoad is called");
}
/*
// 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:[NSArray arrayWithObject: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
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
#end
Change the fetched data method like:
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
latestLoans = [json objectForKey:#"loans"]; //2
arrayOfFighterName=[[NSMutableArray alloc] init];
//NSLog(#"loans: %#", latestLoans); //3
for( int i = 0; i<[latestLoans count]; i++){
// NSLog(#"%#", [matchListArray objectAtIndex:i]);
arrayOfFighterName[i]=[[latestLoans objectAtIndex:i] objectForKey:#"name"];
// NSLog(#"%#", [arrayOfFighterName objectAtIndex:i]);
}
[tableView reloadData];
}
Because the at the first time, the tableView is loaded before the data is added to the array. Due to the asynchronous call. The data is parsed and added to array when the data is retrieved from the server. So you need to reload your tableView to display the data.
Please refer about the asynchronous call in this tutorial.