Reload data in tableview while scrolling with API - objective-c

how to reload the data in the table while scrolling?
If i have a url "http:.......&start=0&limit=50".
How to reload the data in table with incrementing the start and limit value with 50.
Can anyone find a solution for this?

You need to implement the load more functionality in the table view for this.In order to do so, you need to track the table view's index while it is scrolling once table reaches the last cell you can call the api with increased page number and add the new records to the array once you get the positive response from the api.
See the below code for more understanding.
Variable initialization
#interface ExampleListVC (){
BOOL hasNextPage,isLoadingNextPage;
int currentPage;
NSMutableArray *arrTableData;
}
#end
In viewDidLoad method
arrTableData = [[NSMutableArray alloc]init];
currentPage=-1;
hasNextPage = YES;
In tableView numberOfRowsInSection method
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = (int)arrTableData.count;
if (hasNextPage)
{
count++;
}
return count;
}
In cellForRowAtIndexPath method
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
if (indexPath.row<arrTableData.count)
{
//Load TableviewCell you intend to show
}
else
{
//Show loading cell
cell = [self loadingCell:indexPath];
if (!isLoadingNextPage)
{
[self fetchData];
}
}
return cell;
}
Loading Cell Code
-(UITableViewCell *) loadingCell :(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:nil];
cell.backgroundColor = [UIColor clearColor];
UIActivityIndicatorView *activityIndicatorView =[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicatorView.color = [UIColor blackColor];
activityIndicatorView.center = CGPointMake(self.tblView.center.x, cell.center.y);
[cell.contentView addSubview:activityIndicatorView];
[activityIndicatorView startAnimating];
cell.userInteractionEnabled = NO;
return cell;
}
Api call implementation
-(void)fetchData
{
isLoadingNextPage = YES;
if (currentPage==-1)
currentPage=0;
//API Call
{
DLog(#"API Call Response = %#",response);
isLoadingNextPage = NO;
if (response == nil)
{
hasNextPage=NO;
return;
}
if (success)
{
if (hasNextPage)
{
currentPage++;
}
[arrTableData addObjectsFromArray:response];
}
else
{
hasNextPage=NO;
}
//Reload tableview
}];
}
Alternative solution for this is
Use the SVPullToRefresh library in integrate infinite scrolling of it.
https://github.com/samvermette/SVPullToRefresh

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(self.comptabl.contentOffset.y >= (self.comptabl.contentSize.height - self.comptabl.bounds.size.height))
{
if(isPageRefreshing==NO){
isPageRefreshing=YES;
[appDelegate showIndicator:nil view1:self.view];
start=start+50;
[self makeRequest:start];
[self.comptabl reloadData];
NSLog(#"called %d",start);
}
}
}
I am using this method but at all time the value is increment with 50 ..how can i set limit to the value

Related

clicking CANCEL in UISearchController navigates to previous ViewController

I create the UISearchController in ViewDidLoad
//create the search controller
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
self.definesPresentationContext = YES;
[self.searchBarHolder addSubview: self.searchController.searchBar];
self.searchController.searchBar.delegate = self;
when the users clicks the CANCEL button the following delegate method is called.
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
self.searchController.active = NO;
self.myTableView.hidden = YES;
self.transparentViewSearch.hidden = YES;
}
The line self.searchController.active=NO navigates the user back to the previous view controller.
Additionally the line self.transparentViewSearch.hidden = YES does nothing. The view is still visible.
What is going on?
you are using same table for showing search result
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
You need to do update table after cancel search result.
[self.tableview reloadData];
then you need to do something like below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(bShowSearchResult)
{
// return search result count
}
else
{
// return normal list count
}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(bShowSearchResult)
{
 // create cell using search result data
 Data = [lstSearchResults objectAtIndex:indexPath.row];
 //create cell
 // return cell
}
else
{
Data = [lstFiles objectAtIndex:indexPath.row];
//create cell
// return cell
}
}
I think it will help to you

Hide tableview sections on tap gesture of section header

I want to hide the NSArrays (menuItems, about, and charting) on the click for the specific section header for the tableview cell arrays. I got the section header to highlight and de-highlight depending on tap gesture recognizer count but I can not get the tableview cells to hide when that specific section header is clicked. Can someone please help? Thank you! Here is my .m code. My GCF float method is located at the bottom of the .m.
#interface SidebarTableViewController ()
#end
#implementation SidebarTableViewController {
NSArray *menuItems;
NSArray *about;
NSArray *charting;
}
- (void)viewDidLoad {
[super viewDidLoad];
menuItems = #[#"Home",#"Field Goal", #"Punt", #"Kick Off", #"Snapper", #"Punter"];
about = #[#"Home",#"About Us", #"Tutorial"];
charting = #[#"Home",#"Charting"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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];
}
if (indexPath.section==0) {
NSString *CellIdentifier = [menuItems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
else if(indexPath.section==1) {
NSString *CellIdentifier2 = [charting objectAtIndex:indexPath.row];
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2 forIndexPath:indexPath];
return cell2;
}
else {
NSString *CellIdentifier1 = [about objectAtIndex:indexPath.row];
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1 forIndexPath:indexPath];
return cell1;
}
}
#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 {
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3 ;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section==0)
{
return [menuItems count];
}
else if(section==1)
{
return [charting count];
}
else{
return [about count];
}
}
- (UIView*) tableView: (UITableView*) tableView viewForHeaderInSection: (NSInteger) section
{
UILabel *headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [UIColor grayColor];
if(section == 0){
headerLabel.text = [NSString stringWithFormat:#"Timers Without Charting"];
}
else if(section==1)
{
headerLabel.text = [NSString stringWithFormat:#"Charting with Timers"];
}
else{
headerLabel.text = [NSString stringWithFormat:#"About Us/Tutorial"];
}
headerLabel.frame = CGRectMake(0, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(catchHeaderGesture:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
//return nil;
}
-(void)catchHeaderGesture:(UIGestureRecognizer*)sender
{
border ++;
if (border == 1)
{
UILabel *caughtLabel = (UILabel*)sender.view;
caughtLabel.layer.borderColor = [UIColor yellowColor].CGColor;
caughtLabel.layer.borderWidth = 2;
}
if (border == 2 )
{
UILabel *caughtLabel = (UILabel*)sender.view;
caughtLabel.layer.borderColor = [UIColor clearColor].CGColor;
caughtLabel.layer.borderWidth = 2;
border = 0;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
border ++;
if (border == 1)
{
UITableViewCell* cell = [menuItems objectAtIndex:indexPath.row];
cell.hidden = YES;
return 40.0;
}
if (border == 2 )
{ border = 0;
UITableViewCell* cell = [menuItems objectAtIndex:indexPath.row];
cell.hidden = YES;
}
return 0;
}
#end
You need a few couple things to make this work.
section headers that respond to taps.
a method for expanding or collapsing a section.
some way to track which sections are collapsed.
The first is trivial. Return a UIView for the header, and attach a UITapGestureRecognizer to it. You'll need a method to figure out which section it is. You can use the tag property, or you can store the views in an NSMutableArray.
In tableView:numberOfRowsInSection: you return 0 if the section is collapsed, or the actual number, if not.
In the handler for the gesture recognizer, you toggle the collapsed/expanded state, and then you call `[self.tableView reloadSections:withRowAnimation:] to update the visuals.
(I do see in your posted code that you already handle part of this.)

UITableViewCell Leak when deleting and saving the cell

I noticed one of my custom UITableViewCell is leaking. It is not getting released on performing edit, remove bottom cell and tap on Save. This is my top cell in the table (I call it add cell). Once my table view is in edit mode, Add cell is shown up with all the other cells shown underneath with delete mode on. Now, after performing the delete operation and saving the data, Add Cell still hang around even if dealloc on my table view gets called.
I am attaching my code and instrument screenshot (I've removed first line (Malloc call) from the screenshot. To me, it appears to be something wrong in iOS internal handling. Please advise.
- (UITableViewCell *)tableView:(UITableView *)iTableView cellForRowAtIndexPath:(NSIndexPath *)iIndexPath {
MyTableViewCell *aCell = nil;
NSString *aCellType;
if (iIndexPath.row == 0 && self.inEditMode) {
aCellType = kMyAddCell;
aCell = (MyAddCell *)[iTableView dequeueReusableCellWithIdentifier:aCellType];
if (!aCell) {
aCell = [[MyAddCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:aCellType];
}
aCell.isGroupedView = YES;
aCell.delegate = self;
aCell.textLabel.text = #“Add More";
self.tableView.allowsSelectionDuringEditing = YES;
} else {
aCellType = kMyDefaultCell;
aCell = (MyTableViewCell *)[iTableView dequeueReusableCellWithIdentifier:aCellType];
if (!aCell) {
aCell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:aCellType];
}
NSInteger anIndex = iIndexPath.row;
if (self.inEditMode) {
anIndex = anIndex - 1;
}
aCell.textLabel.text = #“Name";
aCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return aCell;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)iIndexPath {
return (iIndexPath.row == 0 && self.inEditMode) ? UITableViewCellEditingStyleNone : UITableViewCellEditingStyleDelete;
}
- (BOOL)tableView:(UITableView *)iTableView canEditRowAtIndexPath:(NSIndexPath *)iIndexPath {
return YES;
}
- (void)tableView:(UITableView *)iTableView commitEditingStyle:(UITableViewCellEditingStyle)iEditingStyle forRowAtIndexPath:(NSIndexPath *)iIndexPath {
if (iEditingStyle == UITableViewCellEditingStyleDelete) {
[self setSaveModeNavigationBar];
[self.tableView beginUpdates];
[self.enabledUsers removeObjectAtIndex:(self.inEditMode) ? iIndexPath.row - 1 : iIndexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[iIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
}
- (void)setEditing:(BOOL)iEditing animated:(BOOL)iAnimated {
[super setEditing:iEditing animated:iAnimated];
[self.navigationItem setHidesBackButton:YES animated:NO];
self.headerViewLabel.text = #“Edit Me";
UIBarButtonItem *aDoneButton = [[UIBarButtonItem alloc] initWithTitle:#“Done"
style:UIBarButtonItemStylePlain
target:self
action:#selector(cancelEditing)];
[self.navigationItem setRightBarButtonItem:aDoneButton];
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
self.inEditMode = YES;
[self.tableView reloadData];
}
Code that gets called once I tap on Save button:
self.requestHandler = [[MyRequestHandler alloc] initWithEndPoint:myEndPoint body:aPostBody successHandler:^(NSDictionary *iResponse) {
[aBlockSelf addNoDataOverlay];
} andErrorHandler:^(NSString *iMessage, NSString *iKey, NSInteger iErrorCode, BOOL iIsNetworkError) {
[aBlockSelf addNoDataOverlay];
}];
[self.requestHandler executeRequest];
Instrument Allocation Stack:
Apparently it turned out to be a known issue being tracked in this thread. Tried the same steps in iPhone 5S (iOS 8) and issue has been resolved there.

I need to implement the expandable tableView cell in ios 8

In my project I need to implement the UITableview with some of the tableView cells are expandable and some of them are independent. If it is expandable cell need to indicate the '+' symbol.enter image description here. Can any one please help me out
I have created a small demo,
https://github.com/haripalwagh/ExpandableTableviewCell
Screenshot 1 : Before expanding a cell
Screenshot 2 : After expanding a cell
#interface ViewController ()
<UITableViewDataSource,
UITableViewDelegate>
{
UITableView *tblView;
NSArray *cell0SubMenuItemsArray;
BOOL isSection0Cell0Expanded;
}
#end
#implementation ViewController
# pragma mark - View Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
tblView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
tblView.backgroundColor = [UIColor clearColor];
tblView.delegate = self;
tblView.dataSource = self;
tblView.allowsSelection = YES;
tblView.scrollEnabled = YES;
tblView.alwaysBounceVertical = YES;
[self.view addSubview:tblView];
cell0SubMenuItemsArray = #[#"First Static Menu Item", #"Second Static Menu Item", #"Third Static Menu Item"];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.view setNeedsLayout];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self updateViewDimensions];
}
- (void)updateViewDimensions
{
tblView.frame = CGRectMake(0, 40, 320, 550);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
# pragma mark - UITableView Delegate and Datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
{
int cellCount = 2; // Default count - if not a single cell is expanded
if (isSection0Cell0Expanded)
{
cellCount += [cell0SubMenuItemsArray count];
}
return cellCount;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellId = #"CellId";
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strCellId];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (indexPath.section == 0)
{
if (indexPath.row == 0)
{
cell.textLabel.text = #"Expandable Cell";
UIImageView *accessoryImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
if (isSection0Cell0Expanded) // Set accessory view according to cell state - EXPANDED / NOT EXPANDED
{
accessoryImageView.image = [UIImage imageNamed:#"Minus.png"];
cell.detailTextLabel.text = #"Status : Expanded";
}
else
{
accessoryImageView.image = [UIImage imageNamed:#"Plus.png"];
cell.detailTextLabel.text = #"Status : Not Expanded";
}
cell.accessoryView = accessoryImageView;
}
else
{
if (isSection0Cell0Expanded && [cell0SubMenuItemsArray count] >= indexPath.row) // Check Expanded status and do the necessary changes
{
cell.textLabel.text = [NSString stringWithFormat:#"%#", [cell0SubMenuItemsArray objectAtIndex:indexPath.row - 1]];
}
else
{
cell.textLabel.text = #"Static Cell";
}
}
}
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
// Change status of a cell reload table
isSection0Cell0Expanded = !isSection0Cell0Expanded;
[tblView reloadData];
}
}
You have to manage like this for every expandable cell.
Hope this will help you..
Try this control: https://github.com/jonasman/JNExpandableTableView
It supports what you say. Tapping on a cell expands it.

Another "reloadData calls numberOfRows, but not cellForRowAtIndexPath"

I know this question has been asked again and again. This post summarized some common causes, but none applies to me:
Every answer I've seen when searching has been a variation of: 1) The tableView is nil 2) numberOfRowsInSection is 0 3) tableView's delegate/data source not set 4) calling reloadTable on the wrong uiTableView.
The answer to that post was the tableView was not displayed before another call to reloadData, which is not my case either. My actual code is a bit lengthy, so I would just paste the parts that I think is related. Feel free to ask me to paste more. Note that competitorsTable has been added to the view in the story board.
#interface CartItemViewController : TrackedUIViewController <UITableViewDataSource, UITableViewDelegate>
//...
#end
#interface CartItemViewController ()
//...
#property (weak, nonatomic) IBOutlet UITableView *competitorsTable;
#end
#implementation CartItemViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// ...
NSAssert(self.competitorsTable, #"Competitor table should not be nil");
self.competitorsTable.dataSource = self;
self.competitorsTable.delegate = self;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self updateCompetitors];
}
- (void)updateCompetitors
{
MBProgressHUD *indicator = [MBProgressHUD showHUDAddedTo:self.hostView animated:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (![self.product isLoaded]) {
[NSThread sleepForTimeInterval:1];
}
[self.product loadCompetitorsPriceForConditionValue:self.conditionValue];
NSDictionary *competitors = self.product.competitors[#(self.conditionValue)];
dispatch_async(dispatch_get_main_queue(), ^{
if (competitors) {
if (competitors.count > 1) {
self.hostView.hidden = NO;
self.hostView.hostedGraph = [[CompetitorGraph alloc]initWithFrame:self.hostView.bounds Competitors:competitors];
NSAssert(!self.competitorsTable.hidden, #"Competitor table should not be hidden");
[self.competitorsTable reloadData];
} else {
self.hostView.hidden = YES;
}
} else {
self.hostView.hostedGraph = nil;
}
[indicator hide:YES];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSDictionary *competitors = self.product.competitors[#(self.conditionValue)];
if (competitors.count == 0) {
NSLog(#"WARNING: %s returning 0", __PRETTY_FUNCTION__);
} else {
NSLog(#"Number of rows: %d", competitors.count);
}
return [self.product.competitors[#(self.conditionValue)] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Sort names according to its price
NSDictionary *competitors = self.product.competitors[#(self.conditionValue)];
NSArray *names = [competitors.allKeys sortedArrayUsingComparator:^NSComparisonResult(id name1, id name2) {
if ([competitors[name1] floatValue] > [competitors[name2] floatValue]) {
return (NSComparisonResult)NSOrderedAscending;
} else if ([competitors[name1] floatValue] < [competitors[name2] floatValue]) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"vendor"];
NSString *vendorName = names[indexPath.row];
cell.textLabel.text = vendorName;
cell.detailTextLabel.text = competitors[vendorName];
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #"Competitors' Offer";
}
#end
When the view is opened, there are two calls to numberOfRowsInSection, one returns 0, which is normal because the competitors information hasn't been loaded, the other returns a number greater than 0. But cellForRowAtIndexPath is called in none of the cases.
After hours of debugging, I finally found the problem: I didn't set the struts and springs right, making the table be squeezed to 0 height. Because it is not shown, cellForRowAtIndexPath was not called