I have an interesting requirement for an app I am working on. I have a UITableView with a bunch of items in it. I am trying to log which items were looked at (scrolled past). For example, if the list contains letters A-Z and the user scrolls down the UITableView to letter T, then values A,B,C,D,E.F....T would be stored as an NSString in NSUserDefaults.
I would like to store the actual row text as the value in the NSString. For example, A instead of 1, B instead of 2, etc...
I have done some digging around but cant seem to find anything useful. Any ideas on how I might accomplish this?
The function
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
is called every time you view a cell. You could then use a method to convert indexPath.row into an alphabetic letter and store that in NSUserDefaults
Edit - on re-reading your question I get the impression youre just talking about generic titles of the rows. Thats easy - because you have to set the title text in cellForRowAtIndexPath - so you could just pop it into defaults when you do this.
Make a plist ( NSDictionary ) and make pairs ( key- value ) like 1 - A 2- B and so on. When you want to store it, write a method, which will search your value, for a key.
if you have dynamic data:
make an NSMutableDictionary, and
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
in:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[dict setObject:cell.label.text forKey:indexPath.row];
}
EDIT:
You can get the visible rows with this method:
indexPathsForVisibleRows
Returns an array of index paths each identifying a visible row in the receiver.
- (NSArray *)indexPathsForVisibleRows
Return Value
An array of NSIndexPath objects each representing a row index and section index that together identify a visible row in the table view. Returns nil if no rows are visible.
I assume you are populating the list from array containg A,B,C and etc.
Do your array would be:
(A,B,C,D,E,F,G)
So, start with converting each index of array into a NSMutableDictionary such that the array becomes as follows, here visited refers to wether that row has been visited or no, by default 0 for No:
(
{
value = "A"
visited = 0
},
{
value = "B"
visited = 0
},
{
value = "C"
visited = 0
},
{
value = "D"
visited = 0
},
)
Now on cellForRowAtIndexPath do this:
NSMutableDictionary *editDict = [arrayObjects objectAtIndex:indexPath.row];
[editDict setInteger:1 forKey:#"visited"];
[arrayObjects replaceObjectAtIndex:indexPath.row withObject:editDict];
This way all the rows that have been visited will have 1 for key "visited"
then you can run a loop to save the values corresponding to visited = 1 wherever you want
Related
I need to create a NSString for browsing folders in FTP share. i show the directory on a TableView, and user´s can browse by selecting row ´s
Im writing the string of selected rows into a mutable array, and then i need to make a string of all strings in the mutable array. means add the last string to the previous when the row is selected
for example first string in array is "Downloads" second "Movies" third "HD-Movies"....... and so on
for that i need the string on the first time selected row "/Downloads/"
the second time "/Downloads/Movies/", an the third "/Downloads/Movies/HD-Movies"
i´m sure i need a NSMutableString, but don´t know how to add the strings...
here a part of my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *filePathArray = [[NSMutableArray alloc]init];
[filePathArray addObject:#"/Downloads/"];
[filePathArray addObject:[fileNameArray objectAtIndex:indexPath.row]];
}
You can do like this:
NSString *string=[array componentsJoinedByString:#"/"];
This will give you :
Downloads/Movies/HD-Movies
Now if you want / in front than you can simply append an /.
I want to access the UITableViewCell that is after the one that is selected and select that one,
int b = lastIndexPath.row + 1; //lastIndexPath references to the current selected cell index path
NSIndexPath *myNextIndex = [[NSIndexPath alloc]initWithIndex:b];
[self tableView:table didSelectRowAtIndexPath:myNextIndex];
so up to this point everything works fine, the b value is 2. but when the tableView:didSelectRowAtIndexPath: and I want to get the value of i,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int i = indexPath.row;
//some other stuff
}
I get the value 81809923 for i, but the value of i should be 2.
I don't know why this would happen. if anyone has any idea please help.
thanks
Positions in a UITablleView are keyed by both section and row (even if your table only has a single section). The iOS SDK adds a utility method specifically for the purpose of making it easier to work with table views.
In this case, you would use it like:
NSIndexPath* myNextIndex = [NSIndexPath indexPathForRow:b inSection:0]; //call 'retain' if you need to
As for your 81809923 value, that is probably random garbage that happened to be in memory, since your original code does not assign any value to the row field of the NSIndexPath.
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 UITableView that, under certain conditions, needs to have something added to the top of it. All data (except for what is inserted at the top of the UITableView under certain conditions) is brought in from an array.
Because everything is brought in from an array, I need to modify the indexPath that fetches those array objects each and every time the method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is called. If I try to create a local variable and update the local version of indexPath.row, it tells me it is read only.
What would be the best way to implement this?
Drawing below (this is not intended to be code, but a drawing of the table view):
(REGULAR SITUATION) (3 lines)
array objectAtIndex:0;
-----
array objectAtIndex:1;
-----
array objectAtIndex:2;
etc. etc
(MODIFIED SITUATION) (4 lines)
blah blah modified insertion text here
-----
array objectAtIndex:0;
-----
array objectAtIndex:1;
-----
array objectAtIndex:2;
etc etc
Thanks in advance.
Why not just add your new item at the start of your array?
// Create a mutable copy and add the item at index 0
NSMutableArray *mutable = [myData mutableCopy];
[mutable insertObject:newItem atIndex:0];
// Then store the new array and reload the table
[myData autorelease];
myData = mutable;
[self.tableView reloadData];
Then you don't have to do anything funny at all with index paths :)
THIS is a great tutorial that addresses your issue.
Use
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
OR
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
Return the String/View as something or empty depending on the condition that you use while deciding when to show it or not.
Don't go down that path. Just use the tableHeaderView property of UITableView to add something on top of the table. It will scroll just like a UITableViewCell.
self.tableView.tableHeaderView = aView;
To remove it, just set it to nil.
If you insist in this method, just keep a BOOL around to tell you in which state you are and if you need the extra line just subtract 1 from indexPath.row, like
[myArray objectAtIndex:indexPath.row-1];
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.