Завершение приложения из-за ошибки «NSInternalInconsistencyException» - PullRequest
1 голос
/ 18 марта 2020

Завершение работы приложения из-за необработанного исключения «NSInternalInconsistencyException», причина: «попытка вставить раздел 50, но после обновления осталось только 1 раздел».

Привет всем, я застрял на этой ошибке весь день. Вылетает приложение после установленного Предела загрузки партии в 50 ячеек. Я считаю, что я заполняю tableView неправильно. Вот фрагмент кода, непосредственно работающего с разделами в таблице.

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
}

}

расширение 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()
    }
}

}

расширение NotificationViewController: GPostHelperProtocol {} расширение NotificationViewController: ProfileHelperProtocol {}

Ответы [ 2 ]

1 голос
/ 18 марта 2020

Вы пытаетесь вставить 50 разделов вместо 50 строк, но ваш метод numberOfSections утверждает, что имеется только один раздел. Вот почему исключение бросается. Убедитесь, что вы вставляете строки, а не разделы.

1 голос
/ 18 марта 2020

Вероятно, предполагалось следующее, но было бы лучше описать то, что должно быть показано, когда есть notifications, а не.

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 ??
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...