Shift NSIndexPath entities - objective-c

I read NSIndexPaths all the time for uitableviews etc. But I'm having difficultly manipulating an existing indexpath.
I want to take an existing indexpath increment/shift each section while preserving the rows. So that indexPath.section 0 becomes indexPath.section 1 etc. moving the associated row count non-desctructively.
I know NSIndexPath is immutable but are their any categories or nice patterns that support this?

Well, you could always just create a new slightly changed instance from the old one.
NSIndexPath *newPath = [NSIndexPath indexPathForRow:oldPath.row
inSection:oldPath.section+1];

Related

Possible implementations of editable UITableView data sources

I'm seeking to implement a UITableView that has sections representing the recent history and future queue of a media player. It seems to me that a Queue-type structure would be most applicable for this, as this represents the nature of the operation, but the requirement that the future queue part be editable poses some challenges.
I think that a linked list would be the best option here to store the media representations, as opposed to a vector type structure where all of the elements are stored contiguously. It seems to me that, in the case of moving or removing an object within the queue and adding object at the end, a linked list is more efficient than a vector, as simply assigning a few pointers different values seems more lightweight than moving entire chunks of memory. The internal implementation details of NSMutableArray seem quite obscure but I'm assuming it's a vector type.
However, I've never really seen a true linked-list implementation in Objective-C. Furthermore, the structure of UITableViewDataSource, requiring cellForRowAtIndexPath: to be called with a specific row rather than simply iterating through the list, exposes the weakness of linked list implementations, as seeking a specific index can be expensive. This would be irrelevant if cellForRowAtIndexPath: is only called in order, but it seems reckless to ignore the indexPath parameter in favor of just iterating through the list.
How are these structures typically implemented? Is iterating through a link list as proposed a bad idea?
Since Objective-C doesn't have an explicitly defined "linked list" object type, the closest alternative would be NSMutableArray.
You should never assume the order in which
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
will be called, and if you implement the UITableView correctly, it should only be called for the index paths of cells right before they appear on screen (thus the order it's called would alter based on the direction the user is scrolling in).
I recommend that you create a 2-dimensional NSMutableArray with the 1st representing the sections in the table and the 2nd representing the rows in each section. You would then initialize the array using something like:
self.sectionsArray = [NSMutableArray array];
[self.sectionsArray addObject:[NSMutableArray array]]; // history rows
[self.sectionsArray addObject:[NSMutableArray array]]; // queued rows
Which would allow you to easily retrieve the stored items using something along the lines of:
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = indexPath.section;
NSUInteger row = indexPath.row;
id fetchedObject = self.sectionsArray[section][row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellReuseID"];
// perform setup here based on the fetchedObject
return cell;
}
I've listed some NSMutableArray methods you may find helpful below:
- (void)addObject:(ObjectType)anObject;
- (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index;
- (void)removeObject:(ObjectType)anObject atIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(ObjectType)anObject;
- (void)removeLastObject;

How do you correctly get a row value from a table view?

I have implemented code that returns 0 every time. I'm trying to remove a string from a mutable array with the row value selected after hitting a button.
Related code:
- (IBAction)remove:(id)sender {
NSIndexPath *selectedIndexPath = [_tableView2 indexPathForSelectedRow];
[names removeObject:[NSString stringWithFormat:#"%i",selectedIndexPath.row]];
testLabel.text=[NSString stringWithFormat:#"%i",selectedIndexPath.row];
[_tableView2 reloadData];
}
The test label shows 0 every time the button is pressed, no matter where the tableview is selected.
Let me know if there is other relevant code (like the tableView) that you want me to post.
For a UITableView, the selected row concept is only valid while the user is touching the row. For that reason indexPathForSelectedRow is documented as returning “An index path identifying the row and section indexes of the selected row or nil if the index path is invalid.”
My opinion is that you are obtaining a nil result, and later calling the row method in that nil results in the zero that your are seeing as your name.
The solution depends on the rest of your data source implementation, but probably will involve storing the tapped index in didSelectRowAtIndexPath: to later use it in your remove method.
(I supposed that you are not using the allowsMultipleSelectionDuringEditing option nor are you editing the table).
Instead of:
[names removeObject:[NSString stringWithFormat:#"%i",selectedIndexPath.row]];
Try:
[name removeObjectAtIndex:selectedIndexPath.row];
Also, instead of using #"%i", try using #"%d" as mentioned here
Hope this helps!

How to reload a UItableView with rows and section

I have a UITableView displaying a list of plants in alphabetical sections. Within the app, the user can change the language. When the language is changed, the method:
[self.tableview reloadData];
now displays the same plants in a new language. The problem is that the rows and sections are intact, and still sorted in the alphabetical order of the previous language. I have googled and read up and down stackoverflow to find a solution. The closest I came was:
[[self tableView]reloadData];
NSRange range = NSMakeRange(0, [self numberOfSectionsInTableView:self.tableView]);
NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:range];
[self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationFade];
Still, I have to run the tableView through viewdDidLoad to change the alphabetical sorting.
What is the best way to force a new alphabetial sorting after [[self tableview]reloadData]; ?
Before calling reloadData you first need to update all of your data used by the table view data source and delegate methods.
You do not need to call viewDidLoad again. Put the code to setup the data structures in its own method. Then you can call this setup method from viewDidLoad (if needed) as well as just before calling reloadData after a language change.

How to get number of rows in NSIndexPath section

I want to get the number of rows in an NSIndexPath section. For all my searching here & in Apple's docs I can't find how to get this value. Any clues on it?
My specific purpose is to use that to determine whether or not the selected row is the last row in the section so if anyone has a suggestion for determining that by another means that would be as good.
Everything is in docs
numberOfRowsInSection:
int rows = [table numberOfRowsInSection:indexPath.section];
The only way is to ask the data source of the table:
NSUInteger rowCount = [tableView.dataSource tableView:tableView numberOfRowsInSection:indexPath.section];
Here's how I do it in my case:
The table section holds a list of objects stored in NSArray, hence the amount of rows in section is the amount of objects in the array. In your case - if row is not the object from array - just do the check
if ([indexPath row] + 1 == [_objectsArray count]) {
...
But if your items in table are not held in a collection, you can easily retrieve number of rows in section just by calling appropriate method on tableView object in your didSelectRow.. delegate method:
NSInteger numberOfRows = [tableView numberOfRowsInSection:[indexPath section]];
You can call tableView:numberOfRowsInSection: method of the UITableViewDataSource, passing the section number. However, it is your own code that produces this number based on what's in the model, so it may make sense to look at the implementation of tableView:numberOfRowsInSection: in your data source to see if you could get the same answer through an alternative path.
If you are talking about on a UITableView, you can ask it's dataSource, which is somewhat likely to be yourself :-)
[self.tableView.dataSource tableView: self.tableView numberOfRowsInSection: indexPath.section];
// or, if you are the dataSource...
[self tableView: self.tableView numberOfRowsInSection: indexPath.section];

Objective-C: How to generate one unique NSInteger from two NSIntegers? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Pass two integers as one integer
Will this work in Objective-C?
Pass two integers as one integer
If so, how do I do it with NSInteger?
I'm asking because I want to calculate a unique NSInteger tag from the NSUIntegers row & section of a UITableView?
See, I'm dealing with a UITableViewController that has three sections, which each have multiple rows. Every row has a UISwitch, and each UISwitch is linked to the same target-action method, switchAction:.
In switchAction:, my plan is to inspect the sender's tag to figure out the UISwitch's NSIndexPath (section & row) of the UITableView.
So, I want two methods like:
+ (NSInteger)integerFromInteger1:(NSInteger)int1 integer2:(NSInteger)int2;
+ (NSIndexPath *)indexPathFromInteger:(NSInteger)integer;
The first method may work better written in C. That works too if you prefer.
Rather than messing around with bit-shifting, try this:
First, find the UITableViewCell containing the UISwitch. If you have a custom UITableViewCell subclass, just direct the UISwitch's target/action to a method on the cell that contains it. If you are using a stock UITableViewCell, you could find the UITableViewCell containing the UISwitch by calling superview in a loop.
Once you have the UITableViewCell, call a method on your view controller (or whatever has access to the UITableView) and you can call UITableView's indexPathForCell: method to get an NSIndexPath object with the section and row.
According to How to convert An NSInteger to an int?, NSInteger will always be at least 32 bits on every system/architecture, so yes, the answers to Pass two integers as one integer will work.
Based on #benzado's answer, I came up with a beautiful solution for how to get the index path of the UISwitch that sent the switchAction: message.
- (void)switchAction:(id)sender {
UISwitch *onOff = (UISwitch *)sender;
NSIndexPath *indexPath = [self.tableView indexPathForCell:
(UITableViewCell *)[onOff superview]];
// carry on...
}
No tags necessary. Just keep your pants on.