Here i am tryning to add a new row but it's crashing and giving the error "attempt to insert row 3 into section 2, but there are only 3 rows in section 2 after the update". Intially the emerCount is 2 and i am trying to add 3rd row.
var index = NSIndexPath()
if (emerCount<3){
emerCount += 1
index = NSIndexPath(row: emerCount, section: 2)
self.profileTableView?.insertRows(at: [index as IndexPath], with: .automatic)
self.profileTableView?.reloadData()
}
Two issues:
Before calling insertRows you have to insert the item in the data source array into the same location (index emerCount in section 2). This is mandatory.
Basically never call reloadData() right after insertRows. Inserting the row updates the table view with an animation. Remove reloadData().
Further be aware that indexes are zero-based and the third row is indeed inserted at index 2.
PS: Why is the table view optional? Is is created programmatically and displayed temporarily? And don't use NSIndexPath in Swift 3.
More context is needed. What is written in your data source (numberOfRows(inSection:)) methods? It seems that you numberOfRows(inSection:) returns 3 for the section but you want to add one more row.
Delete this line : self.profileTableView?.reloadData()
Related
Question 1: How can i have section index in tableview without section?
Question 2: Could i have those section index for specific rows in a table? For example: i want the section index to be implemented whenever indexpath.row > 4.
Table views in UIKit always have sections and rows. By saying you don't want a section, you are really saying that you simply want only one section (at section index 0) that holds all rows (with indexes relative to section index 0).
Note: You can easily have a section without a section header in which case the user will never know that all rows are actually contained in a section.
When you implement your table view data source, you will want to implement numberOfSections and numberOfRowsInSection in order to let the table view know how many sections and rows you want.
See UITableView.
I think you mean with only one single section (you can't have no sections). Here's how I do this:
Create index titles that are just string versions of the array indexes. If there are too many to fit on the screen, iOS will skip some and replace them with bullets to make it clear that there are some indexes not being displayed. You will be guaranteed that the index range is the same as your row range. (Unless you have zero rows).
Instead of returning the section index, return -1. This will do nothing. Programatically scroll to the ROW of the passed in index.
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
if myDataSourceArray.count > 0 {
return Array(1...myDataSourceArray.count).map({String($0)}).map({ String($0) })
}
return []
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
tableView.scrollToRow(at: IndexPath(row: index, section: 0), at: .middle, animated: true)
return -1
}
(I actually set my minimum count to 20, rather than zero, as there's not much point in having an index when all items in the table are on the screen. But you do need to check for at least greater than zero, otherwise it will try to create an index of "1" for a table with no rows, and this will cause a crash.)
You may want different index titles other than just numbers, but hopefully this gives you some idea on how it can be done. Once you have a different number of indexes to what you have rows, you would have to come up with some other more complicated way of relating index numbers or index titles to row numbers.
Question1:To have section index in tableview without section, you can make height of section to 0.
Question2: If indexPath.row>4, get section index as: yourArray[indexPath.section]
I have the following code in my search method that updates the tableview.
for (int x = 0; x < [array count]; x++) {
//network stuff here
self.searchedReservations = [aSearchObjectType objectsFromServerDictionaries:aResultsArray];
[self.aTableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}
Each object in the array represent a section in my table, for most cases the count will be 4, so 4 sections.
Right now, the code is loading the same data for all sections in the table's cells. Instead of the unique data for each section of the table.
Here is the code that loads the cells. I'm missing some logic that maps the data to the right section of the table.
MyClass *object = [self.searchedReservations objectAtIndex:iIndexPath.row];
cell.textLabel.text = object.customerFullName;
I assume you have the code below in your 'cellForRowAtIndexPath' method:
MyClass *object = [self.searchedReservations objectAtIndex:iIndexPath.row];
cell.textLabel.text = object.customerFullName;
Tables are organised into sections, then within each section there are rows. The rows start at zero again for each section.
If you are on section 0, loading cell 0 this code above is not taking the section number into account, only the row number - so it is loading:
[self.searchedReservations objectAtIndex:0]
to populate the cell.
When you are on section 1, loading cell 0 in section one, you are retrieving exactly the same value because you are just using the row number. ie. you're still loading
[self.searchedReservations objectAtIndex:0]
You may think that you are changing the value of the 'searchedReservations' object between the loading of each section (this is what it looks like you're trying to do in the loop above) but I'm not sure that this is working (as the code the populate searchedReservation doesn't seem to do anything different in each loop counter). Also the first time the table loads it will run through all of the rows in all of the sections anyway.
I think you need to either use the indexPath.section field as well as the indexPath.row field at the time you are populating the cell to ensure you are setting the appropriate row in the appropriate section.
Also use the debugger to see whats going on in your cellForRowAtIndexPath method and in your loop and make sure that you are getting/using a different 'searchedReservations' object for each incrementation of the loop and that this matches the 'searchedReservations' object in the cellForRowAtIndexPath method.
As the question states, say I have an NSMutableArray containing 4 rows. I then delete row at position 2 by doing [array removeObjectAtIndex: 2] and I want all subsequent rows to be repositioned so that there is no empty slot in the NSMutableArray. (row 3 to become row 2, and row 4 to become row 3)
Is there a way to quickly do that?
This happens automatically when you call removeObjectAtIndex. From the class reference documentation:
To fill the gap, all elements beyond
index are moved by subtracting 1 from
their index.
It's the behavior of the NSMutableArray !
I have a array (resultArray) which has 21 items of data in it. I want to display it in a 8 sectioned table with different row counts.
How to assign the value properly in all row? Both indexpath.row and section.row gives wrong values. How to assign a single array value to grouped table with more section?
It's up to you to map your data model to the table view, and you can do it any way that you want. If you have a flat array of items and want to map them into different sections of the table view, you'll have to know which offsets of the result data go into which sections of the table, but no one can do that for you automatically, because only you know the semantics of the data. You need some code that takes the section and row index and figures out which index into the results array needs to be returned.
If it's always 21 items and always the same mapping, then hardcoding the mapping in a table or a big bunch of if statements is probably fine. If it's dynamic then you'd need some other lookaside mapping table, depending on how you wanted to map.
Finally, as #iPortable suggests, you could also find a way to structure your results data appropriately, which makes the controller logic simple, depending on your data.
I would create a multi layer array for this. The first level would be the section count and the second level the row. The array would look something like this:
resultArray{
1 = {
1 = first row in first section,
2 = second row in first section
},
2 = {
1 = first row in second section,
2 = second row in second section
}
}
then you get the value from the array in your cellForRowAtIndexPath: as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *sectionArray = [returnArray objectAtIndex:indexPath.section];
cell = [sectionArray objectAtIndex:indexPath.row];
}
I have implemented a standard UITableViewController. I have made only some rows in the table to be moveable, ie. canMoveRowAtIndexPath returns true only for some indexPaths (for rows in the first part of the table). I would like to allow exchange of only those rows that are moveable, ie. for which canMoveRowAtIndexPath returns true.
Eg. my table looks like this:
Row 1
Row 2
Row 3
Row 4
Row 5
Rows 1, 2, 3 are moveable. So I want to implement the following behavior: row 1 can be exchanged only with rows 2 or 3. Similary, row 2 can be exchanged only with rows 1 and 3.
This is one possible layout:
Row 3
Row 1
Row 2
Row 4
Row 5
However, I don't want this to happen:
Row 3
Row 5
Row 2
Row 4
Row 1
How to achieve this?
Keep in mind that it's actually only moving one row, not exchanging.
What you want is to implement tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath
See How to limit UITableView row reordering to a section
You can control the movement within section and between section.
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
// Do not allow any movement between section
if ( sourceIndexPath.section != proposedDestinationIndexPath.section)
return sourceIndexPath;
// You can even control the movement of specific row within a section. e.g last row in a Section
// Check if we have selected the last row in section
if ( sourceIndexPath.row < sourceIndexPath.length) {
return proposedDestinationIndexPath;
} else {
return sourceIndexPath;
}
// you can use this approach or logic to check the index of the rows in section and return either sourceIndexPath or targetIndexPath
}