How can I create live UITableView under iOS ?
I meen, I want to create application which connect to server written in JAVA. Server under POST request return table of maps with data (JSON format). The problem is that, the data could be very large (around 100000 recods). I already implemented on server side returning data in parts (when POST have offset and size params, server returns data from offset to (offset + size) and total count of data).
The problem is that i don't have any idea how can I implement it with iOS.
I know how can I made UITableView working with data downloaded from server, but I don't know how can I made UITableView working with parts of data: something like: on enter to view I download only 100 rows form 100000, when user scrolls down (for example to 80 row) I download next part of data. I mean I don't want to store whole 100000 rows in memory, but only 200 rows which can be displayed in table view. When user scrolls to end of table, in memmory I shoud have rows from 99800 to 100000
When user scroll the tableview we'll check if the last cell is reached or not if the last cell is reached we'll download the next dataset like this :
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
NSInteger sectionsAmount = [tableView numberOfSections];
NSInteger rowsAmount = [tableView numberOfRowsInSection:[indexPath section]];
if ([indexPath section] == sectionsAmount - 1 && [indexPath row] == rowsAmount - 1) {
// This is the last cell in the table
//Here you can download the next part of dataset and reload the tableView.
}
}
Hope this will help you.
Related
I am creating a table view based iPhone application, Where i need to disable one by one entire table view cell.
The requirement is like -
Case-1 :-
Initially only first table cell row should be user interaction enable, rest should be disable. We can easily do this to make indexPath.row 0 enable in CellForRowAtIndexPath method.
Case-2 :-
If User will tap on First cell and when again he will come back then First cell will be disable and second cell should enable(rest table cell will be disable at this time after second cell).
Case-3 :-
Again if user will tap on second table cell and come back to this table then apart from Third cell, others should be disable and so on...
It means i need to disable one by one all the table cell in serial order.It is possible by setting index but it won't be the proper way to do this. So, can you please suggest me what condition i need to give for this ? Please suggest me for further proceeding.
Thanks.
Just maintain an instance variable which holds the cell number that should be enabled.e.g. enabledCell.
Initialize enabledCell to 0. In didSelectRow increment enabledCell and reload the tableView. In cell for row at indexPath only enable the cell if the indexPath is same as the enabledCell value.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// write code to dequeue or create new UITableViewCell here
// then check if index is same as the cell that should be enabled
if(index.Path.row == enabledCell)
cell.userInteractionEnabled = NO;
else
cell.userInteractionEnabled = YES;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//Assuming you have number of rows stored in variable numberOfRows
enabledCell++;
if(enabledCell == numberOfRows)
enabledCell = 0;
[tableView reloadData];
}
There are many ways to do this (from now on, I'm a assuming a linear table view with n rows and only one section).
For example, you can add a BOOL enabled property to your cell model object. In your controller's didSelectRowAtIndexPath: check that property and do nothing if it's set to NO. If it's set to YES then navigate to the appropriate page and exchange the enabled property with the one at index position i + 1 (or position 0 if it's the last entry and you want to cycle).
In one section of my app I have a UITableView which is working fine right now. I would like to set row 0 cell.textLabel.text to #"Some string". Once row 0 has been set I would then like to load the rest of the rows from an array. Currently on load my array populates the table view but I'm trying to set row 0 as a sticky. The closest example I can think of is a forum topic that is set to stay at the top. My array is constructed of returned data from a web service call.
It's been a while since I've messed with table views, and I'm having a blank on this one.
The table view is 1 section, and I get the rows by counting the elements in the array. Since I would like to create an additional cell (row 0) I would call [array count] + 1. I don't know if this approach is the best one which is why I'm reaching out to the community here.
Any insight or a shove in the right direction would be great at this point.
You're on the right track:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array count]+1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if ([indexPath row] == 0) {
// Code for first
[[cell textLabel] setText:#"First cell"];
} else {
[[cell textLabel] setText:[array objectAtIndex:[indexPath row]-1]];
}
return cell;
}
If you want the top of your table to be "sticky", why not consider using that string as a section header or title? In this case, the header stays visible at all times until the next section (e.g. if you had two sections, that is) is fully on the screen.
In any event, in one of my current projects I'm required to do roughly the same thing that you're doing and I have a static string being returned in row 0 (which scrolls off the top of screen when the table view scrolls down).
And in my UITableViewDataSource method, I always add one for the static cell to the number of objects in my array and in my "cellForRowAtIndexPath:" method, I increment the row by one when the indexPath.row is not zero. And if it is zero, I return my static string.
And dark_knight provides some nice sample code that illustrates what I was describing to you. So +1 to him/her.
How can I get the data from address book in batches of say 20 records at a time & display that 20 records in table view. When new 20 records are fetched , I want to add it in existing array & reload the data. How can I do this? Thanks
In the following delegate where you are setting your rows add one extra row
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return yourMutableArray.count+1;
}
The following delegate tells you that currently which cell is being created.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Under this you can add a check condition like
if(indexPath.row > yourMutableArray.count)
{
// This means you are at the end of your table
// Call your webservice here and append the next set of data into the yourMutableArray
// You can also show an activity indicator over the extra cell here, Indicating the loading of new data
[self performSelector:#selector(getDataFromWebservice) withObject:nil afterDelay:1.0];
}
else
{
// Do your cell settings here
}
and somewhere in your code where you are checking for the success of your webserivce add the following line to reload the table
[yourTable reloadData];
Make sure, that you append the new data into your MutableArray, else table will show only the latest data from the webservice. Hope, this will help you.
I have a UITableView and i can add and delete cells. I also have two buttons on each cell to add and subtract 1 from the cells text. But when i go to a different page and then back to the table view page, all the cells text is set back to 1. But i want the cell's text to stay at the value that the user had set it to! Could someone help me? Im not sure what to do whatsoever. Thanks!
You will have to maintain an NSMutableArray (probably of NSIntegers) that saves the values of the cells. Then, whenever the user changes the value, update the value in the array. Also, display the cell label values by reading from the array. Sample codes below-
-(void)plusButtonClicked:(id)sender
{
//figure out the cell index which was updated using sender
//update the array entry
//[self.array objectAtIndex:index]++; self.array is the array you will maintain
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.label.text = [NSString stringWithFormat: #"%d", [self.array objectAtIndex:indexPath.row]];
}
If you want the values to persist even after the app is terminated and restarted, consider using CoreData.
I have a tableView that needs to be updated after information has been inserted from another view. If I perform a
[self.tableView reloadData];
The very next time I insert more information in another view and try to reload the table, all the currently visible rows are duplicated.
In other words, when I start up the app I have:
tableView:
Row 1
Row 2
Then I submit some information that will also show up in the table and suddenly I have:
tableView
Row 1
Row 2
Row 3 <- info I just added
Row 1
Row 2
My numberOfRowsInSection implementation looks like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [ItemsController sharedItemsController].count;
}
My cellForRowAtIndexPath implementation looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ItemsController* controller = [ItemsController sharedItemsController];
NSMutableArray* recentItems = controller.listOfRecentItems;
CustomCell *cell = nil;
NSUInteger row = [indexPath row];
if( row < recentItems.count )
{
Items* item = [recentItems objectAtIndex:row];
if( recentCellData == nil )
recentCellData = [[NSMutableDictionary alloc] initWithCapacity:[indexPath length]];
if( [recentCellData count] > 0 )
cell = [recentCellData objectForKey:[NSString stringWithFormat:#"%d", row]];
if (cell == nil) {
UIViewController * view1 = [[UIViewController alloc] initWithNibName:#"CustomCell" bundle:nil];
cell = (CustomCell*)[view1 view];
[recentCellData setObject:cell forKey:[NSString stringWithFormat:#"%d",row]];
}
// do some other stuff here
}
// Set up the cell
return cell;
}
What's the best way to update the table and avoid duplicating the currently visible rows.
Thank in advance for all the help!
The error isn't in how you're reloading the table, it's in how you're providing data to it. Set a breakpoint in the data source methods and the method that adds new rows to see where you're going wrong.
You'll only end up with five items if tableView:numberOfRowsinSection: returns 5. Thats the simple answer to your question, but I see other problems here. I'm wondering why you have this test: row < recentItems.count. Is that array the same thing as [ItemsController sharedItemsController].count? You really need to be using the same array for both methods.
(Also, it's not a syntax error, but you shouldn't use the property syntax for things that aren't declared as properties. You should write [recentItems count] instead.)
I'm also confused by the code you use to set up the cell. Cells are meant to be reusable. That is, you create one cell, then reconfigure it every time in your implementation of tableView:cellForRowAtIndexPath:. Your code creates a cell for each item in your list. This is very memory-inefficient, and will likely crash your program due to insufficient memory on the iPhone if you keep lots of cells in memory like this.
The recommended approach is to call dequeueReusableCellWithIdentifier:. If that returns nil, then you set up a cell using the initWithFrame:reuseIdentifier: initializer. The table view is very smart, and will only ask you to redraw the cell when it needs you to.
Your recentCellData dictionary looks really shaky to me, too. What if you insert an item after the item with key #"2"? All the items with key #"3" onward will need to be shifted one element to the right to work the way you expect. That's a ton of bookkeeping that seems rather unnecessary to me. If you really needed something like this -- and to be clear, I don't think you do -- why wouldn't you use an NSMutableArray, which is much easier to use?
I added a bit more info above.