Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert section 50 but there are only 1 sections after the update'
Hey everyone I have been stuck on this error all day. It crashes the app after the set Batch Load Limit of 50 cells. I believe I am populating the tableView incorrectly. Here is a snippet of the code directly working with sections in the table.
import UIKit import Firebase import Foundation
class NotificationViewController: GradientViewController {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var GVX3: UIView!
var isVisible = false
var notifications: [GActionNotification] = []
//Pull to Refresh
lazy var refresher: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.tintColor = primaryColor
refreshControl.addTarget(self, action: #selector(requestData), for: .valueChanged)
return refreshControl
}()
//Pull to Refresh
@objc func requestData() {
print("requesting data")
let deadline = DispatchTime.now() + .milliseconds(856)
DispatchQueue.main.asyncAfter(deadline: deadline) {
self.refresher.endRefreshing()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
isVisible = true
NotificationService.shared.setSeen(notifications: notifications)
setNotificationsBadge()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
isVisible = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
tableView.clipsToBounds = true
tableView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
if #available(iOS 13.0, *) {
tableView.backgroundColor = UIColor.systemBackground
} else {
// Fallback on earlier versions
tableView.backgroundColor = UIColor.white
}
tableView.allowsSelection = false
if #available(iOS 10.0, *) {
tableView.refreshControl = refresher
}else{
tableView.addSubview(refresher)
}
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
observeNotifications()
}
var loader: BatchCollectionLoader?
func requestMoreNotifications() {
loader?.getNextSnapshot(completion: { [weak self] (snapshot) in
NotificationService.shared.process(snapshot: snapshot, completion: { (notifications) in
guard notifications.count > 0 else { return }
guard let strongSelf = self else { return }
var indexSet = IndexSet.init(integer: strongSelf.notifications.count)
if notifications.count > 1 {
let range = (strongSelf.notifications.count...(strongSelf.notifications.count + notifications.count - 1))
indexSet = IndexSet.init(integersIn: range)
}
let shouldUpdate = strongSelf.notifications.count == 0
strongSelf.notifications.append(contentsOf: notifications)
if shouldUpdate {
strongSelf.tableView.reloadData()
} else {
strongSelf.tableView.beginUpdates()
strongSelf.tableView.insertSections(indexSet, with: .bottom)
strongSelf.tableView.endUpdates()
}
})
})
}
func observeNotifications() {
guard let current = GUser.current else { return }
loader = BatchCollectionLoader.init(collection: NotificationService.shared.notificationReference.document(current.uid).collection("notifications"))
loader?.getNextSnapshot(completion: { [weak self] (snapshot) in
NotificationService.shared.process(snapshot: snapshot, completion: { (notifications) in
guard let strongSelf = self else { return }
strongSelf.notifications = notifications.sorted(by: {$0.time > $1.time})
DispatchQueue.main.async {
strongSelf.tableView.reloadData()
}
if strongSelf.isVisible && isInForeground {
NotificationService.shared.setSeen(notifications: notifications)
}
strongSelf.setNotificationsBadge()
})
})
}
func setNotificationsBadge() {
UIApplication.shared.applicationIconBadgeNumber = notifications.filter({!$0.isSeen}).count
if notifications.filter({!$0.isSeen}).count > 0 {
self.tabBarController?.tabBar.items?[2].badgeValue = "\(notifications.filter({!$0.isSeen}).count)"
} else {
self.tabBarController?.tabBar.items?[2].badgeValue = nil
}
}
func configureTableView() {
tableView.register(UINib.init(nibName: LaunchNotificationCell.identifier, bundle: nil), forCellReuseIdentifier: LaunchNotificationCell.identifier)
tableView.register(UINib.init(nibName: GNotificationCell.identifier, bundle: nil), forCellReuseIdentifier: GNotificationCell.identifier)
tableView.rowHeight = 70
tableView.delegate = self
tableView.dataSource = self
}
}
extension NotificationViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return notifications.count > 0 ? notifications.count : 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if notifications.count == 0 {
if let cell = tableView.dequeueReusableCell(withIdentifier: LaunchNotificationCell.identifier, for: indexPath) as? LaunchNotificationCell {
return cell
}
}
if let cell = tableView.dequeueReusableCell(withIdentifier: GNotificationCell.identifier, for: indexPath) as? GNotificationCell {
cell.configure(notification: notifications[indexPath.row])
cell.authorProfileTapped = { [weak self] uid in
guard let strongSelf = self else { return }
strongSelf.openProfile(id: uid)
}
cell.postTapped = { [weak self] postUid in
guard let strongSelf = self else { return }
let notification = strongSelf.notifications[indexPath.row]
if notification.action == .friendRequest {
strongSelf.openProfile(id: notification.user)
} else {
let alert = UIAlertController(title: nil, message: "Loading post...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = UIActivityIndicatorView.Style.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
strongSelf.present(alert, animated: true, completion: nil)
PostService.shared.getPost(id: postUid, location: nil, completion: {post, err in
alert.dismiss(animated: true, completion: nil)
if let post = post {
guard let commentsVC = strongSelf.storyboard?.instantiateViewController(withIdentifier: "CommentsViewController") as? CommentsViewController else {return}
commentsVC.post = post
strongSelf.navigationController?.pushViewController(commentsVC, animated: true)
}
})
}
}
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if notifications.count == 0 {
return view.frame.height
}
return 70
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.section == tableView.numberOfSections - 1 &&
indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 {
requestMoreNotifications()
}
}
}
extension NotificationViewController: GPostHelperProtocol {} extension NotificationViewController: ProfileHelperProtocol {}
Probably it was intended the following, but it would be better to describe what is supposed to be shown when there are notifications
and not.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if notifications.count != 0 { // << here !!
if let cell = tableView.dequeueReusableCell(withIdentifier: LaunchNotificationCell.identifier, for: indexPath) as? LaunchNotificationCell {
return cell
}
}
return UITableViewCell() // << default ??
You are trying to insert 50 sections instead of 50 rows but your numberOfSections
method claims there is only one section. That's why an exception is being thrown. Make sure you are inserting rows, not sections.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.