NSFetchedResultsController问题:索引1超出边界,管理自定义表视图单元格

时间:2018-02-26 02:31:16

标签: uitableview core-data swift4 nsfetchedresultscontroller

我很难实现NSFetchedResultsController,因为我一直在收到错误。我正在尝试使用UITableView连接Core Data,并且我没有通过让UITableView根据Core Data中的记录数抽出正确的行数来实现下一步。我收到此错误消息:

<form enctype="multipart/form-data" action="/processing.php?page=vmrp" method="post" accept-charset="UTF-8" id="formvmrp">
    <input type="checkbox" name="changePIN" onclick="document.getElementById(\'pintext\').style.display = (this.checked) ? \'block\' : \'none\'; document.getElementById(\'nopintext\').style.display = (this.checked) ? \'none\' : \'block\'; " /> Change My PIN
    <div id="nopintext" style="display: block;">
         <button onclick="submitForm(\'vmrp\',\'uvml\')">Unlock Voicemail</button>
    </div>
    <div id="pintext" style="display: none;">
         <label for="edit-submitted-user-name">New PIN: <span class="form-required" title="This field is required.">*</span></label>
         <br>PIN Must be 6 numbers<br>
         <input required="required" type="password" placeholder="New 6 Digit PIN" id="edit-submitted-user-name" name="PIN" value="" pattern="[0-9]{6}" maxlength="6" size="75" title="PIN Must Contain 6 numbers!" class="form-text required" /><br>
         <button onclick="submitForm(\'vmrp\',\'uvml\')">Change PIN</button>
    </div>
    <input type="hidden" name="form_id" value="uVMResetPIN" />
    <input type="hidden" name="uVMPINURI" value="' . (string)$_SESSION['uVMPINURI'] . '" />
    <input type="hidden" name="rmtIP" value="' . $_SERVER['REMOTE_ADDR'] . '" />
    <input type="hidden" name="tz" value="' . $_SESSION['uVMtzn'] . '" />
    <input type="hidden" name="user" value="' . $_SESSION['inUser'] . '" />                                                                     
</form>

以下是我的代码:

*** Terminating app
due to uncaught exception 'NSRangeException', reason: '*** 
[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'

下面显示包含CoreDataStack实现的文件:

import UIKit
import CoreData

class CustomerProfileViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    var coreDataStack: CoreDataStack!

    var itemList: [NSManagedObject] = [] // I hope to have the fetch results controller manage this object

    // The data model contains one entity "Item" with one attribute "name"

    lazy var fetchResultsControllerItem: NSFetchedResultsController<Item> = {

        // Initialize Fetch Request
        let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()

        // Configure Fetch Request
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]

        // Initialize Fetch Results Controller
        let fetchResultsControllerItem = 
            NSFetchedResultsController(fetchRequest: fetchRequest,
            managedObjectContext: self.coreDataStack.managedContext,
            sectionNameKeyPath: nil,
            cacheName: nil)
        fetchResultsControllerItem.delegate = self
        return fetchResultsControllerItem
    }()

    override func viewDidLoad() {

        super.viewDidLoad()

        do {
            try fetchResultsControllerItem.performFetch()
            print("Fetch worked! ")
        } catch let error as NSError {
            print("Could not save. \(error), \(error.userInfo)")
        }

        let cellNib = UINib(nibName: "SummaryCell", bundle: nil)
        tableView.register(cellNib, forCellReuseIdentifier: "SummaryCell")
        let cellNib = UINib(nibName: "ListingsCell", bundle: nil)
        tableView.register(cellNib, forCellReuseIdentifier: "ListingsCell")
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2 // Corresponds to the custom table view cells as Nib files
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if section == 0 {
            return "SUMMARY"
        } else if section == 1 {
            return "ITEM LISTINGS"
        } else {
            return ""
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return 1
        } else if section == 1 {

/* Adding the "guard let sections" to the "return
sectionInfo.numberOfObject" below causes an error: *** Terminating app
due to uncaught exception 'NSRangeException', reason: '*** 
[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]' */
enter code here
            guard let sections = fetchResultsControllerItem.sections else {
                return 0
            }
            let sectionInfo = sections[section]
            return sectionInfo.numberOfObjects

        } else {
            return 1
        }
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "SummaryCell", for: indexPath) as! SummaryCell
            cell.totalNumberOfItems?.text = "\(itemList.count)"
            return cell
        } else if indexPath.section == 1 {

            let cell = tableView.dequeueReusableCell(withIdentifier: "ListingsCell", for: indexPath) as! ListingsCell
            let listItem = fetchResultsControllerItem.object(at: indexPath)
            cell.itemName?.text = listItem.name
            return cell
        }
        return UITableViewCell()
    }
}

在检查sqlite文件后,我确实使用Liya确认有记录名称的项目。对于任何有任何提示或想法的人,我将不胜感激任何帮助。感谢。

1 个答案:

答案 0 :(得分:0)

问题在于,在FetchedResultsController的视图中,如果世界上只有一个部分:第0部分。但是你的tableView有两个部分,你希望FRC为第1部分提供数据。所以你需要重新映射FRC indexPaths到表视图中的正确部分,在tableView数据源方法中。因此,在numberOfRowsInSection中,您的代码当前正在向FRC询问第1部分中的对象数量,并且FRC会抛出错误,因为就其而言,没有第1部分。只需替换:

        let sectionInfo = sections[section]
        return sectionInfo.numberOfObjects

使用:

        let sectionInfo = sections[0]
        return sectionInfo.numberOfObjects

在那个方法中。然后在cellForRowAt中,将其替换为:

        let cell = tableView.dequeueReusableCell(withIdentifier: "ListingsCell", for: indexPath) as! ListingsCell
        let listItem = fetchResultsControllerItem.object(at: indexPath)
        cell.itemName?.text = listItem.name
        return cell

用这个:

        let cell = tableView.dequeueReusableCell(withIdentifier: "ListingsCell", for: indexPath) as! ListingsCell
        let listItem = fetchResultsControllerItem.fetchedObjects![indexPath.row]
        cell.itemName?.text = listItem.name
        return cell

(这使用FRC的fetchedObjects属性来避免在object(at:))中使用indexPath中的错误部分。