*** 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds fo

Posted

技术标签:

【中文标题】*** 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray”【英文标题】:*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray' 【发布时间】:2017-10-18 20:05:01 【问题描述】:

我不断收到此错误:

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

但我不知道我做错了什么。 tableViewnumberOfSections1 并且它们不按日期排序时工作得很好,但是当我尝试每天做部分时,它应用启动时崩溃。

  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)"
        

【问题讨论】:

哪一行崩溃了?正如错误中提到的,您有一个空数组,并且您正在尝试访问它的第一个索引。 我不知道哪条线路崩溃了,它崩溃时将我带到 AppDelegate。不说台词 添加异常断点 @vadian i.imgur.com/VWWrGqs.png hackingwithswift.com/example-code/xcode/… 【参考方案1】:

func numberOfSections(in tableView: UITableView) -> Int guard let count = fetchedResultsController.sections?.count else return 1 返回计数 尝试安全展开:

【讨论】:

【参考方案2】:

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

要通过强制解包(在使用! 的所有地方)修复此外观,并执行以下操作:

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

这将确保 something 在没有崩溃风险的情况下被退回。在某些地方,您可能很难确定默认返回值应该是什么,但它应该是可行的。

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

let foo = someOptionalThing ?? defaultThing

如果someOptionalThing 有一个值,则将其分配给foo,否则将defaultThing 分配给foo

根据您的 cmets 更新:

看起来你打电话给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

【讨论】:

您尝试更改强制展开的每个 位置,还是复制了我上面显示的方法?您提到该特定方法是您从返回硬编码 1 更改但不访问数组元素的方法,因此它不太可能是您的问题的实际原因。 我复制了这条线。我尝试对其他强制展开执行相同的操作,但它们对我来说是奇怪的变量,例如 NSFetchedResultsSectionInfo 我不知道应该使用什么默认值 我猜你的问题出在userBudgetCountgetUserBudgetAtIndexPath。这些是直接或间接访问数组的方法。为它们中的每一个添加一个断点,当它们被触发时,使用 Step Over 并查看它是否超过了线路或崩溃。如果您遇到崩溃,您将知道问题出在哪里,并添加一个防范措施来防止它发生。 userBudgetCount 可以很好地处理断点,但是当我向getUserBudgetAtIndexPath 函数添加断点时,我会被超出范围的索引抛出,因此代码无法以某种方式调用该函数,否则我的应用程序由于我的断点会停止 Xcode 让我解开其中的一些值,否则代码将无法构建。这就是我打开 guard fetchedResultsController.sections!.count &gt; indexPath.sectionguard fetchedResultsController.sections![indexPath.section].objects!.count &gt; indexPath.row 的代码仍然给我同样的错误。【参考方案3】:

我解决了!

问题不在于 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
                    
                
            

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

【讨论】:

不错的尝试。但这并不能保证无崩溃代码。如果您从项目内部的任何地方传递一个大于总节数的数字会发生什么?你可以按照我的回答。谢谢 传递的数字大于总节数是什么意思?我传递的是对象编号,而不是部分【参考方案4】:

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

用下面的代码行替换 uncommentthis 函数。请注意,这些代码行尚未编译。

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;

【讨论】:

我收到Value of type 'NSFetchedResultsSectionInfo' has no member 'object' @AndreiVataselu 我已经更新了我的答案。 NSFetchResultsSectionInfo 是一个协议,它有一个名为 objects[array] 的属性。从那里获取项目,请参阅我的更新答案。谢谢 现在我收到了Value of type '[Any]?' has no member 'object' @AndreiVataselu 很抱歉给出错误的答案。请看我的最新回答 别抱歉,我很感激你能帮助我。不幸的是,我仍然遇到同样的错误。

以上是关于*** 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds fo的主要内容,如果未能解决你的问题,请参考以下文章

由于未捕获的异常而终止应用程序 [UIImageView _isResizable]

由于未捕获的异常而终止应用程序,同时加载视图

由于未捕获的异常“NSInternalInconsistencyException”错误而终止应用程序

“由于未捕获的异常而终止应用程序”在推送视图控制器时崩溃

由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序