UITableView+.plist+UINavigationController issue - objective-c

As my first app I am trying to master simple Navigation Based numismatic collection app.
There's some trouble with indexes in my array filled from .plist. Plist has 191 records; the ordinary list of countries -> item 0 - String - Albania ... item 190 - String - Vanuatu.
I read these records into my temporary array to populate UITableView.
NSString *countriesFile=[[NSBundle mainBundle]pathForResource:#"countries" ofType:#"plist"];
countries=[[NSArray alloc]initWithContentsOfFile:countriesFile];
This table view has sections -> continents.
Well, my problem is:
When pushing to another nib, it should read the name of country and show it in header and label. So it does, but only for european countries. If I tap some other continent's country, I see some european country. Please see screenshots
Tapping on european country -> Belgium, shows right.
Moving to african section:
Taping on Angola and getting Austria.
So, Angola's index - 92. Austria - 1. But Austria and Angola are both second cell in their native section.
Where's the problem and what would it be?
Thanks in advance.

I am assuming you are using -(void)tableView: (UITableView*)tableView didSelectRowAtIndexPath: (NSIndexPath*)indexPath to tell when you have clicked on an item in the list?
Also, are you using [indexPath row] (or indexPath.row) to figure out the index of the row you tapped on?
What the row property returns is the row index within the current section. It does NOT return the absolute row index for the entire table. Because of this, it does not matter if you click on the index two item in the first section or the index two item in the second section, row will return 2 in both of those cases.
An idea would be to change the .plist file a bit. Instead of it only having one long array of countries, have a parent array that represents the continents. Then the object for each index in this continent array, have another array that will hold the list of countries in there.
-(void)tableView: (UITableView*)tableView didSelectRowAtIndexPath: (NSIndexPath*)indexPath
{
NSUInteger section=[indexPath section];
NSUInteger row=[indexPath row];
NSString* countryName=[[plistArray objectAtIndex: section] objectAtIndex: row];
//rest of code...
}

It sounds like you are not taking into account the section value of indexPath. An indexPath has two parts, a section and a row. In tables that have a single section you usually just read the row value. In your case it looks like you have a grouped table so you need to read both indexPath.section and indexPath.row for the data location.

Related

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 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];

Count of dictionaries in NSMutableArray

I have a NSMutableArray *objectsArray; containing dictionaries, each NSDictionary have a "Name" string with the objects name as value (no surprise). UITableView is already sorted using NSSortDescriptor by name in ascending order.
Now I need to section the TableView using the name's first letter, but I cannot find the needed code for:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
/*Return: How many letters from a-z are represented
as the first letter of the objects name?
I.e. If there is no object in the dictionary with name starting with letter B,
the number of sections are now 25 if all the other letters are included.*/
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//Return: How many objects are starting with each letter
So I need to know how to return the correct number of section and rows?
Ps. Is there anything else that I have to do to make this it work, like in cell creation process cellForRowAtIndexPath or when passing the objectsArray through the segue to the DetailViewController?
Additional info about app structure:
objectsArray is from a plist array with dictionaries. using a custom prototype cell to populate the Table View. Xcode 4.2 with storyboard. App for iPhone 5.1
Create a NSMutableSet before you sort. Have your comparator store, in your set, the first letter of each Name it encounters as it sorts. Then the number of sections is the size of your set. This way, you pay very little cost since your comparators are already having to iterate through the array anyway.

Single NSTableView with multiple data sources

Does it make sense logically to have two data sources populating a single NSTableView? Or would a pop up button (with ability to choose from which data source to read)be more reasonable?
If I go with the single NSTableView option, would I be better off if I input all the data into a single data source (say an NSDictionary) and then populating the table? The only problem that I see with this idea is what happens when a selection of the table is done.. How would I decipher which of the original location was selected.
Another idea/potential problem that just popped into my head ... if I take the data from the data source and populate the table directly, how would give the count of the table in the relevant NSTableView 'count' method.. Would adding the count of data store 1 and data store 2 do it?
Sorry if it's a bit jumbled up.. Thanks for any input!
You can definitely use multiple data sources for the data to be displayed in the table view, but they must all be funnelled through a single controller object that is assigned as the table view's datasource and which implements the NSTableViewDatasource protocol.
You will have to write some code in your controller object so that you keep track of the multiple source arrays that make up and supply the table view with the appropriate values for the number of items and the content of each item.
This is a very simplistic example:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [array1 count] + [array2 count];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
if(rowIndex >= [array1 count])
{
return [array2 objectAtIndex:rowIndex - [array1 count]];
}
else
{
return [array1 objectAtIndex:rowIndex];
}
}
As for selection, well, your controller knows where it's getting its data from, so when the user selects a particular row it should be trivial to translate that row index to a matching object in one of your backing stores.
Depending on your application logic, it can make sense. The easiest way would be to set up a different source for every table section. Then, you could use the section number as a selector to your data base.

Animating NSTableView with beginning and ending array states

I've been looking over NSTableView's moveRowAtIndex:toIndex method for animating rows in a table. It's not really helpful for sorting though from what I can tell. My interpretation of how it works is, if I want to move row 0 to row 4, then the rows in between are handled appropriately. However, if I have a table view with an array backing it, and then I sort the array, I want the table view to animate from the old state to the new state. I don't know which items were the ones that moved vs the ones that shift to accommodate the moved ones.
Example:
[A,B,C,D] --> [B,C,D,A]
I know that row 0 moved to row 3 so I would say [tableView moveRowAtIndex:0 toIndex:3]. But if I apply some custom sort operation to [A,B,C,D] to make it look like [B,C,D,A], I don't actually know that row 0 moved to row 3 rather than rows 1,2, and 3 moving to rows 0,1, and 2. I would think that I should just be able to specify all of the movements (row 0 moved to row 4, row 1 moved to row 0, etc.) but the animation doesn't look correct when I try that.
Is there a better way to do this?
Edit: I found this site, which seems to do what I want but seems like a bit much for something that should be simple (at least I think it should be simple)
The documentation for moveRowAtIndex:toIndex: says, "Changes happen incrementally as they are sent to the table".
The significance of 'incrementally' can be best illustrated with the transformation from ABCDE to ECDAB.
If you just consider the initial and final indexes, it looks like:
E: 4->0
C: 2->1
D: 3->2
A: 0->3
B: 1->4
However, when performing the changes incrementally the 'initial' indexes can jump around as you transform your array:
E: 4->0 (array is now EABCD)
C: 3->1 (array is now ECABD)
D: 4->2 (array is now ECDAB)
A: 3->3 (array unchanged)
B: 4->4 (array unchanged)
Basically, you need to tell the NSTableView, step-by-step, which rows need to be moved in order to arrive at an array identical to your sorted array.
Here's a very simple implementation that takes an arbitrarily sorted array and 'replays' the moves required to transform the original array into the sorted array:
// 'backing' is an NSMutableArray used by your data-source
NSArray* sorted = [backing sortedHowYouIntend];
[sorted enumerateObjectsUsingBlock:^(id obj, NSUInteger insertionPoint, BOOL *stop) {
NSUInteger deletionPoint = [backing indexOfObject:obj];
// Don't bother if there's no actual move taking place
if (insertionPoint == deletionPoint) return;
// 'replay' this particular move on our backing array
[backing removeObjectAtIndex:deletionPoint];
[backing insertObject:obj atIndex:insertionPoint];
// Now we tell the tableview to move the row
[tableView moveRowAtIndex:deletionPoint toIndex:insertionPoint];
}];