由于未捕获的异常"NSRangeException"而终止应用,原因:"*** -[__NSArray0对象索引:]:索引 0 超出空 NSArray 的边界"



我不断收到此错误:

2017-10-18

22:57:52.401421+0300 费用经理[4213:133067] * 由于未捕获的异常"NSRangeException"而终止应用程序,原因:"* -[__NSArray0对象索引:]:索引 0 超出空 NSArray 的边界"

但我不知道我做错了什么。当章节数1 并且它们不按日期排序时,tableView 工作得很好,但是当我尝试每天做节时,它在应用程序启动时崩溃。

  func userBudgetCount(_ section: Int) -> Int {
            return fetchedResultsController.sections![section].numberOfObjects
        }
        func getUserBudgetAtIndexPath(indexPath : IndexPath) -> Budget {
            return fetchedResultsController.object(at: indexPath) as Budget
        }

        override func viewDidLoad() {
            super.viewDidLoad()
            self.hideKeyboard()
            tableView.delegate = self
            tableView.dataSource = self
            self.tableView.tableFooterView = UIView()

        }
        override func viewDidAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            fetchCoreDataObject()
            tableView.reloadData()
        }
        func fetchCoreDataObject() {
            self.fetch { (complete) in
                if complete {
                    if userBudgetCount(0) >= 1 {
                        userBudgetLabel.text = replaceLabel(number: userMoney[userMoney.count - 1].userMoney)
                        tableView.isHidden = false
                        plusButton.isHidden = false
                        moreBtn.isHidden = false
                    } else {
                        tableView.isHidden = true
                        userBudgetLabel.text = "Bugetul tau"
                        plusButton.isHidden = true
                        moreBtn.isHidden = true
                    }
                }
            }
        }

        var fetchedResultsController: NSFetchedResultsController<Budget> {
            if _fetchedResultsController != nil {
                return _fetchedResultsController!
            }
            let fetchRequest = NSFetchRequest<Budget>(entityName: "Budget")
            // Set the batch size to a suitable number.
            fetchRequest.fetchBatchSize = 20
            // Edit the sort key as appropriate.
            let sortDescriptor = NSSortDescriptor(key: "dateSubmitted" , ascending: false)
            fetchRequest.sortDescriptors = [sortDescriptor]
            // Edit the section name key path and cache name if appropriate.
            // nil for section name key path means "no sections".
            let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext!, sectionNameKeyPath: "dateSection", cacheName: nil)
            aFetchedResultsController.delegate = self
            _fetchedResultsController = aFetchedResultsController
            do {
                try _fetchedResultsController!.performFetch()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                fatalError("Unresolved error (nserror), (nserror.userInfo)")
            }
            return _fetchedResultsController!
        }
        var _fetchedResultsController: NSFetchedResultsController<Budget>? = nil
        func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
            tableView.reloadData()
        }
     func numberOfSections(in tableView: UITableView) -> Int {
            return fetchedResultsController.sections!.count
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "expenseCell") as? ExpenseCell else { return UITableViewCell() }
            let budget = getUserBudgetAtIndexPath(indexPath: indexPath)
            cell.delegate = self
            cell.configureCell(budget: budget)
            return cell
        }
        func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
            return true
        }
        func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
            return UITableViewCellEditingStyle.none
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return userBudgetCount(section)
        }
        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
            return "Section: (section)"
        }

func numberOfSection(in tableView: UITableView) -> Int {guard let count = fetchedResultsController.section?.count else {return 1}返回计数}尝试安全解开:

当视图首次加载表视图数据源方法时,在结果控制器获取任何数据之前开始调用表视图数据源方法。因此,无论您在何处强制打开某些东西,您都可能会崩溃。

要解决此问题,请查看每个位置,请执行强制解包(使用!的所有位置),并执行更多类似操作:

func numberOfSections(in tableView: UITableView) -> Int {
    return fetchedResultsController.sections?.count ?? 0
}

这将确保某些东西在没有崩溃风险的情况下返回。在某些地方,您可能需要更难确定默认返回值应该是什么,但这应该是可行的。

??运算符称为零合并运算符。语法如下:

let foo = someOptionalThing ?? defaultThing

如果someOptionalThing有一个值,它就会被分配给foo否则defaultThing被分配给foo

根据您的意见进行更新:

看起来你调用return fetchedResultsController.object(at: indexPath) as Budget结果控制器还没有对象,这就是我所期望的。

func getUserBudgetAtIndexPath(indexPath : IndexPath) -> Budget {
    // Make sure the section exists
    guard fetchedResultsController.sections?.count > indexPath.section else { return Budget() }
    // Make sure the section has enough objects
    guard fetchedResultsController.sections[indexPath.section].objects?.count > indexPath.row else { return Budget() }
    // We made it past both guards, must be safe
    return fetchedResultsController.object(at: indexPath) as Budget
}

我解决了!

问题不在于填充函数tableView,而在于函数中,我尝试检查我的实体中是否有元素,以便我可以使我的 tableView 可见

在此代码中

  func fetchCoreDataObject() {
            self.fetch { (complete) in
                if complete {
                    if userBudgetCount(0) >= 1 {
                        userBudgetLabel.text = replaceLabel(number: userMoney[userMoney.count - 1].userMoney)
                        tableView.isHidden = false
                        plusButton.isHidden = false
                        moreBtn.isHidden = false
                    } else {
                        tableView.isHidden = true
                        userBudgetLabel.text = "Bugetul tau"
                        plusButton.isHidden = true
                        moreBtn.isHidden = true
                    }
                }
            }
我尝试检查

用户预算计数(0),这是越界的,因为目前我尝试检查它是否存在时没有第 0 节。所以我需要的是检查我的fetchedResultsController是否有任何对象,所以我用if ((fetchedResultsController.fetchedObjects?.count)! > 0)替换了if userBudgetCount(0) >= 1,它现在可以正常工作。谢谢大家的回答!

对不起。实际上问题出在userBudgetCount方法上。此方法使用 0 参数调用来自fetchCoreDataObject抛出异常的方法的值,因为部分数组最初为空。

将取消注释此函数替换为以下代码行。请注意,这些代码行尚未编译。

func userBudgetCount(_ section: Int) -> Int{
 guard let sections = fetchedResultsController.sections           else {
     fatalError("No sections in   fetchedResultsController")
  // comment out the above line of  and  rerun 0 if don’t want to catch  exception 
  // rerun 0;
  }
    let sectionInfo = sections[section]
  return sectionInfo.numberOfObjects
}

编辑 在我这边编译后,我在下面添加了更新的代码。请使用它而不是上面。

func userBudgetCount(_ section: Int) -> Int{
    guard let sections = fetchedResultsController.sections else {
        return 0;
    }
    if sections.count > section{
        let sectionInfo = sections[section]
        return sectionInfo.numberOfObjects
    }
    return 0;
}

最新更新