I am writing an iOS app in Swift.
Whenever the page loads it gets the list of movies from server and it populates that list into tableView.
I wrote the code for getting JSON from server in a static library (Objective-C) and am receiving json to app via Notification design pattern.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ReceivedNListOfMoviesNotification(_:)), name: Notification.Name(VUSDK.basicNotificationName()), object: nil)
requestForData()
}
func ReceivedNListOfMoviesNotification(_ notification:NSNotification)
{
if let info = notification.userInfo {
basicArray=info["Search"] as! [Any]
if basicArray.count>0 {
tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath.init(row: self.basicArray.count-1, section: 0)], with: .automatic)
tableView.endUpdates()
}
}
}
But app is crashing:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.7.47/UITableView.m:1737
2017-04-23 13:49:12.562 VUDemo[4835:164247] *** 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 (10) 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).'
Replace
if basicArray.count>0 {
tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath.init(row: self.basicArray.count-1, section: 0)], with: .automatic)
tableView.endUpdates()
}
with
if !basicArray.isEmpty {
tableView.reloadData()
}
because you are overwriting the entire array rather than adding a single item.
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 am working on a code where I have to insert & delete all rows on selecting a section.
Below is the code for inserting & deleting
var paths = [IndexPath]()
for row in 0..<(arrayOfSection?.count)! {
let indexPath = IndexPath(row: row, section: selectedIndex!)
paths.append(indexPath)
}
// Toggle collapse
if previousSelectedIndex != nil && previousSelectedIndex == section {
self.arrayOfCategories?.removeAll()
self.catergoryTableView.beginUpdates()
self.catergoryTableView.deleteRows(at: paths, with: .fade)
self.catergoryTableView.endUpdates()
}
else{
self.catergoryTableView.beginUpdates()
self.catergoryTableView.insertRows(at: paths, with: .fade)
self.catergoryTableView.endUpdates()
header.setCollapsed(false)
//scroll
let sectionRect = self.catergoryTableView.rect(forSection: selectedIndex!)
self.catergoryTableView.scrollRectToVisible(sectionRect, animated: true)
}
previousSelectedIndex = selectedIndex
Inserting rows works fine but when I am trying to delete rows from selected section in am getting below error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 9 from section 0 which only contains 0 rows before the update'
What am I doing wrong?
Update your code to delete all row as follows:
self.catergoryTableView.beginUpdates()
self.catergoryTableView.deleteRows(at: paths, with: .fade)
self.catergoryTableView.endUpdates()
self.arrayOfCategories?.removeAll()
Just add first line of code to the last.
so I have an app with radiobuttons to check off tasks, everything's working as expected as long as I let the animation finish but if I press two buttons at the same time I get an error:
libc++abi.dylib: terminating with uncaught exception of type NSException
The Code executed every time a radiobutton is tapped
func RadioTapped(_ cell: TableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
// Removes task from coreData
let task = self.tasks[indexPath.row]
print(tasks.count)
self.context.delete(task)
print(tasks.count)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do{
self.tasks = try self.context.fetch(TodayTask.fetchRequest())
// Animates the removal of task cell
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800),execute: {
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
})
} catch {
print("Fetching Failed")
}
}
}
Error Message
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 (11) must be equal to the number of rows contained in that section before the update (13), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Table row delete operation also requires to delete element of array of table.
According to your code, self.tasks may be an array for your table list.
Delete an element of 'self.tasks' from same indexes, for which you are deleting your rows.
Hint:
// Remove array element
self.tasks.remove(at: <index.row>)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800),execute: {
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
})
I am just starting to learn to swift; I want to add a search bar that allows users to search through the data in my Firebase database. The search bar has added but the code to filter the search result keeps crashing with this error:
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 (0) 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).
The error is pointing to this line
self.tableView.insertRows(at: [IndexPath(row: self.businessArray.count-1, section: 0)], with: UITableViewRowAnimation.automatic)
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference(fromURL:"")
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
ref.child("Businesses").queryOrdered(byChild: "Basic-Info/business").observe(.childAdded, with: { (snapshot) in
//insert the rows
self.tableView.insertRows(at: [IndexPath(row: self.businessArray.count-1, section: 0)], with: UITableViewRowAnimation.automatic)
}) { (error) in
print(error.localizedDescription)
}
}
Before inserting the rows in the table view you have to insert the items at the same indexes into the data source array.
However in this case I'd recommend to assign the query result to the data source array and call reloadData()
As #vadian said, you have to modify your datasource to match what you are trying to reflect in the UI. So if we are inserting a row into a UITableView, then you must first insert an object into the datasource at the same index of the row you are adding. Like so:
// First modify datasource
let businessObjectToInsert = BusinessObject() // or whatever your class is
self.businessArray.append(businessObject)
// Then insert row into `UITableView`
self.tableView.insertRows(at: [IndexPath(row: self.businessArray.count-1, section: 0)], with: UITableViewRowAnimation.automatic)
I'm getting an error when I try to delete a cell from my UITableView. I've looked at numerous links (this one for example is what I'm going off of. Below is my code:
var countdownTime = expirDate - currentDate
timer.setCountDownTime(countdownTime)
println("Count : \(self.offers.count)")
timer.startWithEndingBlock { (countdownTime) -> Void in
//If the times have expired, then delete the row
self.tableView.beginUpdates()
self.offers.removeAtIndex(indexPath.row)
self.tableView.deleteRowsAtIndexPaths([indexPath.row], withRowAnimation: UITableViewRowAnimation.Fade)
self.tableView.endUpdates()
}
timer.start()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return offers.count
}
//Only one section
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
I want to remove the cell when my timer has completed and the offers array is the array that I use to populate the UITableView. I was going off of this Assertion Failure -[UITableView _endCellAnimationsWithContext] which I thought would help me delete/insert rows correctly but I still get an error saying:
*** 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 (1) must be equal to the number of rows contained in that section before the update (1), 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).'
Any help would be appreciated!
EDIT: An issue I might be having that I am trying to delete the cell while I am inserting the cell into the UITableView. I am inserting the cell, setting the cell contents, then deleting the cell if the timer for that cell has existed for over 24 hours. This is bad because the cell will then try to insert the next cell when it thinks that there is 1 cell in the table view. Are there any better ways to do this?
EDIT 2: Code for inserting into table:
...//Code to insert into database
override func viewDidLoad() {
super.viewDidLoad()
//setupOffers()
setupOffers { (result, offer) -> Void in
if(result == true){
//Insert each row one by one.
var currentCount = self.offers.count
var indexPaths: [NSIndexPath] = [NSIndexPath]()
indexPaths.append(NSIndexPath(forRow:currentCount, inSection: 0))
self.offers.append(offer)
currentCount++;
//Update based on each table view index.
self.tableView.beginUpdates()
self.tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Bottom)
self.tableView.endUpdates()
//Method 2 to update uitableview
//self.tableView.reloadData()
}
}
// Do any additional setup after loading the view, typically from a nib.
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.rowHeight = 145.0
}
Add the statement self.offers.removeAtIndex(indexPath.row) before starting the updates on the table view self.tableView.beginUpdates() as
self.offers.removeAtIndex(indexPath.row)
self.tableView.beginUpdates()
As it could happen that you start the update on table view and the number of rows are returned before deleting the object from the array, and thus could result in inconsistency.
I believe this is simply a caching problem. Your fetchedResultController is not going to automatically refetch your results as it caches its results. That means that when tableView:numberOfRowsInSection: is called again, the results count is still returning number even though you deleted an item.
Use this code...
self.tableView.beginUpdates()
self.tableView!.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Fade)
self.tableView.endUpdates()
Error when deleting item from tableview in swift
This might helps you :)
Try self.tableView.beginUpdates() after self.offers.removeAtIndex(indexPath.row)
EDIT:
Remove beginUpdates and endUpdates, as self.tableView.deleteRowsAtIndexPaths([indexPath.row], withRowAnimation: UITableViewRowAnimation.Fade) should be enough to refresh the table.
EDIT 2: Check that the count of offers is correct after the update. Print its count before and after you delete the item and after return offers.count.