I have an UITableView set up with a NSArray with 10 indexes. Right now, the first cell on the uitableview is the first index, the second cell is the second index, and so on so forth. Is there any way to make it so that the first cell displays the latest index? Maybe through some code in the uitableview delegate because I am adding data to the NSArray. What that means is that there aren't 10 indexes right off the bat.
If anyone as an answer, help is much appreciated.
Each time that you get a new item of data, you add it to the start of your array, not to the end. Then just call [self.tableView reloadData] and it should just work.
You can use insertObject:atIndex: to add to the start of the array:
[myArray insertObject:newData atIndex:0];
(see here for docs)
Somewhere in your code you're probably doing something like this (where items is your NSArray object):
cell.textLabel.text = [items objectAtIndex:indexPath.row];
Instead, do:
cell.textLabel.text = [items objectAtIndex:([items count] - 1) - indexPath.row];
Related
I have a UITableView with each cell is having a UITableViewCellAccessoryCheckmark. The user can check and uncheck the cells depending on his preference. The user can check/select multiple cells in the tableview. A selected/checked cell can be unchecked and rechecked again on user preference.
I have a done button in the UITableViewController. On its click, I need to return to the previous view, before that I have to have a collection of the text in the checked cells(only checked cells).
How can I do this.
I was planning on developing a logic, by keeping an NSMutableArray and update it on - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath, when a cell gets checked/selected. But when every time a cell is unchecked I have to remove the item from the array and if the cell is checked again, then I have to add it again. I reckon thats not the right way to do this. What would be the right way to do this.
I couldn't find a question of similar kind here in Stackoverflow, which is very unusual. Would be helpful if someone could post a link, if the question was asked before.
Maintain two arrays, like this:
#property (nonatomic, retain) NSMutableArray *features, *selectedFeature;
synthesize them in .m file. initialize your both arrays something like this in viewDidLoad:
self.features = [NSArray arrayWithMyOwnResourceLikeDownloadedFromServerOrWhatever];
self.selectedFeature = [NSMutableArray array];
Then do something like this in didSelectRowAtIndex:
NSString * stirng = [features objectAtIndex:indexPath.row];
if ([self.selectedFeature containsObject:stirng]) {
[self.selectedFeature removeObject:stirng];
}
else{
[self.selectedFeature addObject:stirng];
}
and in your cellForRowAtIndexPath:
NSString * stirng = [features objectAtIndex:indexPath.row];
[cell.textLabel setText:stirng];
if ([self.selectedFeature containsObject:stirng]) {
//it is selected feature
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
else{
//it is un-selected feature
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
Create a boolean array of the same length as the number of checkable cells and update the value on click events. If the table content is dynamic, you can use methods provided by NSMutabeArray to keep the boolean array in accordance with the table content. Upon return use the array to grab the text you need.
i have a table view in which i can add 1 or subtract 1 to the value of my cell.textLabel.text but when i switch views and return or scroll a cell out of the view, and when it comes back into view, the textLabel's value returns to 1 which is the original starting point! Please help! Here is the code to add and subtract 1:
- (IBAction)addLabelText:(id)sender{
cell = (UITableViewCell*)[sender superview]; // <-- ADD THIS LINE
cell.textLabel.text = [NSString stringWithFormat:#"%d",[cell.textLabel.text
intValue] +1];
}
- (IBAction)subtractLabelText:(id)sender
{
cell = (UITableViewCell *)[sender superview];
if ( [[cell.textLabel text] intValue] == 0){
cell.textLabel.text = [NSString stringWithFormat:#"%d",[cell.textLabel.text intValue] +0];
}
else{
cell.textLabel.text = [NSString stringWithFormat:#"%d",[cell.textLabel.text intValue] -1];
}
}
This is happening because, the cells will be re-used on scrolling. The table view's datasource method will be invoked, hence the values get reset to the original value. You can maintain an array of NSNumbers as a datasource to the tableview (is, in cellForRowAtIndexpath: , set the text fo the cell label from the array). Each time you need to add or subtract, do it the corresponding NSNumber obj and re-load the tableview.
Seems like you are allocating a new cell each time.. and not using the cell re-usablility method.
In your case, when you are performing arithmetic actions to your previous values and you don't have an array to store previous values. The easiest way to fix this is make your Cell-Identifier unique. (something like #"Cell-%d",indexPAth.row)
Note: However, more efficient way would be to save your result in the array you are populating your data from, without making you Cell-Identifier unique.
You are not updating your data modal. That is why it is taking the original content value.
After change the cell text value reload the tableview [self.tableview reloadData]
I'm filling a TableView with CoreData.
Until now I was doing something like this:
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
...to retrieve the object to fill the row.
Everything was working fine until I realized I have to manage the first row of the table as an exception because the first line will contain other content, not provided by CoreData.
Now my issue is how can I manipulate the indexPath to shift everything by one. I would like to do something like this:
// I know this is not going to work, just to give you an idea...
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath-1];
but I cannot find the right syntax to manipulate the indexPath. Can anyone help me?
Thx for your time!
In case we are talking about iOS UITableView index path there's much easier way:
NSIndexPath* newIndexPath = [NSIndexPath indexPathForRow:oldIndexPath.row+1 inSection:oldIndexPath.section];
Cheers... :)
If you're talking about a standard iOS UITableView, then your index path is an instance of NSIndexPath, and will have two entries: a section index and a row index. If I understand you right, you want to decrement the row index by 1 every time you go to fill a table view cell. (I'm assuming you only have one section, or don't care about the section index - if this is wrong, please edit your question.)
Basically what you need to do is construct a new NSIndexPath instance with your adjusted indices, then use that to query your fetched results controller. Something like this would work (untested):
NSUInteger indexes[2];
[indexPath getIndexes:indexes];
indexes[1]--;
NSIndexPath * adjustedIndexPath = [[NSIndexPath alloc] initWithIndexes:indexes
length:2];
NSManagedObject * managedObject = [self.fetchedResultsController
objectAtIndexPath:adjustedIndexPath];
This basically does the following:
Pulls the existing indexes into a C array of NSUIntegers
Decrements the last index (at position 1 - the row index) by 1
Creates a new NSIndexPath with the adjusted indexes from the C array
Fetches the managed object using the new index path
Note again that this doesn't touch the section index at all, and so will adjust every cell in your table, regardless of whether it's in your first section. If that's not what you want, either wrap the adjustment in a conditional (e.g. if([indexPath indexAtPosition:0] == 0)) or add your own custom logic.
I just checked the datasource and the UITableView of the app and they seem to be working well.
I can add a row to the TableView by using the code - [...initWithObjects:(id),nil] and I could do this at code level.
This is what I want to do.
Create an Add button or a '+' sign on top of the table.
So while the App is running.. If I click that, I should be able to set a name for that row.
If I need to create more rows and set names for them, I just press the add button and I again type new names for the rows .
How do I go about this in real time?
The UITableView method -insertRowsAtIndexPaths:withRowAnimation: is used to add rows to a table programmatically.
This answer addresses your problem fairly directly.
It's fairly straightforward... and this is from memory, so I might have a typo here or there. The idea should work though.
In tableView:numberOfRowsInSection: you give return [myArray count] + 1; (you're adding one row to the total)
In tableView:cellForRowAtIndexPath: the cell where [indexPath row] == [myArray count] is where make a cell with "Add Row" text, rather than whatever your data source is, because it goes to [myArray count]-1. (I think that makes sense).
for example,
if([indexPath row] == [myArray count]){
cell.textLabel.text = #"Add New Item";
} else {
cell.textLabel.text = [[myArray objectAtIndex:[indexPath row]]
valueForKey:#"title"];
}
return cell;
Then you would insert the new record into your myArray and the table.
As for actually changing the new row details, you have some options of creating a custom cell with some kind of textual input or using a modal view controller with a prompt. It's really up to you.
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.