Syncing UITableView with the Array - ios

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.

Related

Invalid update: invalid number of items in section 0

I am hitting the following error when attempting to drag items from one UICollectionView (collectionView) into another (rackView):
'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (7) must be equal to the number of items contained in that section before the update (6), plus or minus the number of items inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'
The strange thing is, almost the exact same code works for dragging and dropping when I am dragging the items from rackView into collectionView. rackView updates correctly when items are deleted from rack datasource but crashes when items are added back into it from the board (collectionView). Does anyone know why this is happening and is there any way to solve it?
Thanks for any information you can provide.
I've tried to add a variable which represents the count that's in the rack and return that in the numberOfItemsInSection method. This is stated as a possible solution for this error elsewhere but doesn't seem to resolve it for me.
private func moveItemsFromRack(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
{
collectionView.performBatchUpdates({
for (index, item) in coordinator.items.enumerated()
{
let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
self.board[indexPath.row] = item.dragItem.localObject as! String
self.rack.remove(at: self.sourceIndex.row)
}
DispatchQueue.main.async {
collectionView.reloadItems(at: [destinationIndexPath])
self.rackView.reloadData()
}
})
self.sourceIndex = []
}
private func moveItemsFromBoard(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
{
collectionView.performBatchUpdates({
for (index, item) in coordinator.items.enumerated()
{
let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
self.rack.insert(item.dragItem.localObject as! String, at: indexPath.row)
self.board[self.sourceIndex.row] = ""
}
DispatchQueue.main.async {
collectionView.reloadItems(at: [self.sourceIndex])
self.rackView.reloadData()
}
})
self.sourceIndex = []
}
I actually just removed the performBatchUpdates method and this issue was resolved.
An explanation for why is here:
https://fangpenlin.com/posts/2016/04/29/uicollectionview-invalid-number-of-items-crash-issue/

Collection view performBatchUpdates crash randomly in swift

I am making chat application. for chat Ui, I used jsqmessageview controller. when we load previous messages then give the following error:-
[JSQMessagesCollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3698.52.10/UICollectionView.m:5867
2019-02-25 17:25:35.553375+0530 Calmex[288:12648] ** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert item 25 into section 0, but there are only 25 items in section 0 after the update'
we used following code :-
var indexPaths: [AnyObject] = []
var arraysizeOfCollectionview : Int = 0
if(isloadmore)
{
self.collectionView.performBatchUpdates
({
indexPaths.removeAll()
let lastIdx = messages123.count - 1
for i in 0...lastIdx
{
print("index path -->\(IndexPath.init(item: i, section: 0))")
indexPaths.append(IndexPath.init(item: i, section: 0) as AnyObject)
}
self.collectionView.insertItems(at: indexPaths as! [IndexPath])
self.collectionView.collectionViewLayout.invalidateLayout(with: JSQMessagesCollectionViewFlowLayoutInvalidationContext())
arraysizeOfCollectionview = arraysizeOfCollectionview + indexPaths.count
},
completion: {(finished) in
})
}
else
{
arraysizeOfCollectionview = self.messages.count
}
we have total row count in "arraysizeOfCollectionview" and return in the collection view.
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
// Return the number of messages
return arraysizeOfCollectionview
}
so anyone has a solution for this random crash then please help me or any idea of related to load the previous message using collection view then please help me.
thank you.

Deleting cell leads to a crash

So my numberOfRowsInSection is:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let delegate = delegate else { return 0 }
return delegate?.comments.count + 1
}
I added one more to compensate for the "load more" which is on top of the table view (in this case, it's row 0).
Here's the thing: when I want to remove that cell "load more" after fetching the max amount of posts, it gives me an error:
The number of rows contained in an existing section after the update (12) must be equal to the number of rows contained in that section before the update (11), 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).'
So here's the function that causes the error:
func loadMore() {
// loadMoreComments(completion:) inserts the new comment objects inside
// the data source in the beginning of the list.
delegate?.loadMoreComments(completion: { (isEndOfPosts, newCommentCount, comments) in
self.didReachEndOfPosts = isEndOfPosts
if isEndOfPosts {
// indexPaths just returns [[0,1]], or, just one row.
let indexPaths = self.createIndexPathsForNoMorePosts(newCommentCount: newCommentCount)
self.tableView.beginUpdates()
// error happens here.
self.tableView.deleteRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
self.tableView.endUpdates()
// assume only one post comes in, and that's the last one.
self.tableView.beginUpdates()
self.tableView.insertRows(at: indexPaths, with: .automatic)
self.tableView.endUpdates()
}
}
What I'm trying to accomplish is this: once i get the last post, remove the "load more" cell, and insert the last few posts, replacing the 0 row with the first of the last few posts.
You need to notify your tableView's datasource about cell count change. Create a class variable, something like
var shouldShowLoadMoreCell = true
and than modify numberOfRowsInSection method
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let delegate = delegate else { return 0 }
if shouldShowLoadMoreCell {
return delegate?.comments.count + 1
} else {
return delegate?.comments.count
}
}
finally, set this flag when needed
self.tableView.beginUpdates()
shouldShowLoadMoreCell = false
self.tableView.deleteRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
self.tableView.endUpdates()

Insert dynamic textfield cells into section in TableView - Swift

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

app crash on iOS Swift insert rows at index path with animation

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.

Resources