I am a beginner in Swift and i am stuck with a problem.
I have a TableView Controller which contains 3 sections, the first two are composed of one textfield in one cell.
However, for the third one at the beginning, it has only one cell (textfield).
Each time the user presses Return on the textfield, i would like to insert one row composed of one textfield below the textfield edited. (Like when you add multiple phone numbers in the Contacts App).
I created a UITextField Array : TextFieldArrayPayers
My code looks like this :
Connected to the textField when user presses Return :
#IBAction func AddParticipant(sender: AnyObject) {
tableView.beginUpdates()
textFieldArrayPayers.append(UITextField());
tableView.insertRowsAtIndexPaths([
NSIndexPath(forRow: textFieldArrayPayers.count, inSection: 2)
], withRowAnimation: .Automatic)
tableView.endUpdates()
}
And to manage my sections :
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section==2
{
return textFieldArrayPayers.count+1
}
else
{
return 1;
}
}
When I run my program, i try to edit the first textfield and when I press Enter or Return, I get this :
Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
I looked at numerous similar topics but never found the real solution..
Thanks in advance for those who got the solution
Update your model before beginning your batch update:
#IBAction func AddParticipant(sender: AnyObject) {
textFieldArrayPayers.append(UITextField());
tableView.beginUpdates()
tableView.insertRowsAtIndexPaths([
NSIndexPath(forRow: textFieldArrayPayers.count, inSection: 2)
], withRowAnimation: .Automatic)
tableView.endUpdates()
}
For more information on see the Table View Programming Guide for iOS
Related
When I remove an object from a list and try to add a new one in I get this error
2020-01-24 14:40:26.692343+1300 HappyDays[25416:1017241] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
I see other issues similar to this but I've tried implementing those solutions . (Similar issue , another similar issue)
Sections of my code:
Selecting the cell to delete if from the table
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
activeObjectives.actives.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .left)
}
Adding a new object to the table by tapping a button
#IBAction func getGoals(_ sender: UIButton) {
let newRowIndex = activeObjectives.actives.count
activeObjectives.setRandomGoalToActive(allObjectiveList: allGoalsArray)
addActiveGoalToactiveObjectives()
let indexPath = IndexPath(row: newRowIndex, section: 0)
let indexPaths = [indexPath]
activeGoalDisplay.insertRows(at: indexPaths, with: .automatic)
}
In case it's also needed, here is my addActiveGoalToactiveObjectives function called in the above
func addActiveGoalToactiveObjectives() {
for goal in allGoalsArray.goalsList {
if goal.isActive == true && activeObjectives.actives.contains(goal) == false {
activeObjectives.actives.append(goal)
}
}
}
Thanks in advance, any help is greatly appreciated
I found the issue. I wasn't setting an object value to false when removing it from the list. Now when I remove them I set the object to inactive.
activeObjectives.actives[indexPath.row].setInactive()
activeObjectives.actives.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .left)
}```
I have a question about making a table view section expand/collapse. There are many pieces of information on the web about this topic, but my question is a little bit different.
My question is, how can I make an additional section when the user taps on another section?
The following images may help you understand my situation.
At the top of the table view we have one small section (section 0).
If I tap it...
Section 1 and 2 should be created between section 0 and 3.
How can I do this? Is there any way or code? Please help me.
Also, I tried this code but got a sigabrt error :(
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.beginUpdates()
let indexSet = NSMutableIndexSet()
indexSet.add(indexPath.section + 1)
indexSet.add(indexPath.section + 2)
if indexPath.section == 0 {
if expandCol == true {
self.tableView.deleteSections(NSIndexSet(index: 1) as IndexSet, with: .automatic)
self.tableView.deleteSections(NSIndexSet(index: 2) as IndexSet, with: .automatic)
expandCol = !expandCol
} else {
self.tableView.insertSections(NSIndexSet(index: 1) as IndexSet, with: .automatic)
self.tableView.insertSections(NSIndexSet(index: 2) as IndexSet, with: .automatic)
expandCol = !expandCol
}
}
self.tableView.endUpdates()
self.tableView.reloadData()
}
You can keep a flag variable on view-controller for selectedSection.
var selectedSection: Int = -1
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return section == selectedSection ? <section-row-count> : 0
}
Set the flag value in section header action method:
func actionSectionHeader(tag: Int) {
selectedSection = tag
self.tableView.reloadData()
}
To add a new section into UITableView, you need
1 - Update your data. For example, insert your sections in a data array, or change their visibility flags.
2 - Call the following method.
tableView.insertSections([1, 2], with: .automatic)
or
tableView.reloadData()
The first method will update your UITableView with an animation. The second one will update it instantly. For better UX I'd recommend you to use the first one.
Update on your code
At first, you can pass all sections indices at once using a simple array. Like that
if expandCol {
self.tableView.deleteSections([1, 2], with: .automatic)
} else {
self.tableView.insertSections([1, 2], with: .automatic)
}
expandCol = !expandCol
The second problem is that you're calling reloadData after you call the animated update of your table.
And the most important, you need to change the data. You UITableView has a dataSource and it returns a number of sections and cells. After user interacts with your trigger cell, you need to make changes at that data before calling the update.
The problem is quite simple.
I am attempting to animate the addition of a new row into a new section.
The update code:
func updateTableView(sessions: [Sessions]) {
self.foundSessions = sessions
if self.numberOfSections(in: self.tableView) == 0 {
self.tableView.beginUpdates()
self.tableView.insertSections([0], with: .automatic)
self.tableView.endUpdates()
}
for i in 0..<self.foundSessions.count {
self.tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath(row: i, section: 0)], with: .automatic
self.tableView.endUpdates()
}
}
UITableViewDataSource code:
override func numberOfSections(in tableView: UITableView) -> Int {
if foundSessions.isEmpty { return 0 }
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foundSessions.count
}
And the error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert section 0 but there are only 0 sections after the update
Obviously, it seems the section is not getting inserted. If I take out insertRows, the empty section eventually shows up, as can be seen by the tableFooterView at the top. I have followed the advice of the posts here, here, here, and here, and have read the respective Apple Documentation on the manner, obviously to no avail.
Any iOS gurus out there able to show me the error in my ways?
EDIT: More debugging info - updateTableView is called in the callback of an async function. I wrapped all this code in a DispatchQueue.main.async block in an attempt to remedy the situation, however, was unsuccessful.
Try putting all your updates to section and it's row in one block, begin ... end like below
self.tableView.beginUpdates()
self.tableView.insertSections([0], with: .automatic)
for i in 0..<self.foundSessions.count {
self.tableView.insertRows(at: [IndexPath(row: i, section: 0)], with: .automatic
}
self.tableView.endUpdates()
I have a UITableView which is shown when the screen is loaded. The UITableView shows 7 items since the dishes array contains 7 items. I have button which adds one more item to the dishes array.
// adding just one more item to the array
self.dishes.append(contentsOf: filteredArray)
let newIndexPath = IndexPath(row: self.dishes.count + 1, section: 0)
self.tableView.insertRows(at: [newIndexPath], with: .automatic)
As soon as the new dish is added I get the following error:
'NSInternalInconsistencyException', reason: 'attempt to insert row 10 into section 0, but there are only 9 rows in section 0 after the update'
*** First throw call stack:
I would like to see more of the code to understand what you're doing but I think you should be doing it more like this.
var dishes = [Dish]()
#IBAction func myButton(_ sender: Any) {
dishes.append(Dish())
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dishes.count
}
The last row index will be self.dishes.count without adding 1.
I have a table view controller with static cells in 5 sections. I would like to add a second row to one of the sections when a UISegmentedControl object in the first row of that section is tapped (value change action function). I do not have a data source for this as I only intend to use the new row to display a text field. At this time I am only looking to see an empty row appear with animation, so that I may add the text field programmatically later on.The iOS simulator crashes whenever I tap the segmented control. No error message. Xcode 7 iOS 9. I've looked up other responses to similar queries but unable to identify the issue. Any help appreciated. My code is below. Thanks!
class MyTableViewController: UITableViewController, UITextFieldDelegate {
// init with 1 row in section 3 of table view. This row contains the segment
// control object
var rowsInMySection = 1
// index path for new row (second row) to be added to section 3
var indexPath1 = NSIndexPath(forRow: 1, inSection: 3)
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 5
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var rows = 1
if section == 3 {
rows = rowsInMySection
}
else {
rows = 1
}
return rows
}
#IBAction func segmentControlTapped(sender: UISegmentedControl) {
if(segmentControl.selectedSegmentIndex == 1)
{
self.tableView.beginUpdates()
self.tableView.insertRowsAtIndexPaths([indexPath1],
withRowAnimation : UITableViewRowAnimation.Automatic)
self.rowsInMySection = 2
self.tableView.endUpdates()
}
}
You answered your own question. You have a static tableView so by definition it can't be added to or removed from.