***由于未捕获的异常'NSRangeException'终止应用程序,原因:'*** - [__ NSArray0 objectAtIndex:]:索引0超出空NSArray的边界'

时间:2017-10-18 20:05:02

标签: ios swift uitableview core-data

我一直收到这个错误:

  

2017-10-18 22:57:52.401421 + 0300费用管理器[4213:133067] *由于未捕获的异常'NSRangeException'而终止应用程序,原因:'* - [__ NSArray0 objectAtIndex:] :索引0超出空NSArray'

的边界

但我不知道我做错了什么。当 numberOfSections 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)"
        }

4 个答案:

答案 0 :(得分:0)

func numberOfSections(在tableView:UITableView中) - &gt; Int { guard let count = fetchedResultsController.sections?.count else {return 1} 返回计数 } 尝试安全打开包装:

答案 1 :(得分:0)

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

要修复每个地点的这种外观你强行打开(在你使用!的任何地方)并做更多这样的事情:

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

这将确保某些被返回而不会有崩溃的风险。在某些地方,您可能会遇到更具挑战性的时间来确定默认返回值应该是什么,但它应该是可行的。

??运算符称为nil-coalescing运算符。语法如下所示:

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
}

答案 2 :(得分:0)

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

使用以下代码行替换uncommentt此函数。请注意,这些代码行尚未编译。

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;
}

答案 3 :(得分:0)

我解决了!

问题不在tableView填充函数中,但在函数中我尝试检查如果我的实体中有元素,那么我可以使 tableView < / strong>可见

在此代码中

  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
                    }
                }
            }

我尝试检查超出界限的 userBudgetCount(0),因为我尝试检查它是否存在时, NO 部分为0。所以我需要的是检查我的 fetchedResultsController 是否有任何对象,所以我将if userBudgetCount(0) >= 1替换为if ((fetchedResultsController.fetchedObjects?.count)! > 0),现在工作正常。谢谢大家的回答!

相关问题