NSFetchedResultsController 问题:索引 1 超出范围,管理自定义 table 视图单元格
NSFetchedResultsController issue: index 1 beyond bounds, managing custom table view cells
我对实施 NSFetchedResultsController 感到困惑,因为我不断收到错误。我正在尝试将 Core Data 与 UITableView 连接起来,但我没有通过让 UITableView 根据 Core Data 中的记录数绘制出正确的行数来进入下一步。我收到此错误消息:
*** Terminating app
due to uncaught exception 'NSRangeException', reason: '***
[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
下面是我的代码:
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()
}
}
下面显示了包含 CoreDataStack 实现的文件:
import Foundation
import CoreData
class CoreDataStack {
private let modelName: String
init(modelName: String) {
self.modelName = modelName
}
lazy var managedContext: NSManagedObjectContext = {
return self.storeContainer.viewContext
}()
private lazy var storeContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: self.modelName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
print("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func saveContext() {
guard managedContext.hasChanges else { return }
do {
try managedContext.save()
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}
}
}
检查sqlite文件后,我确实使用liya确认了有名称记录的项目。对于任何有任何提示或想法的人,我将不胜感激。谢谢
问题是,在 FetchedResultsController 的视图中,只有一个部分:第 0 部分。但是您的 tableView 有两个部分,您希望 FRC 为部分提供数据1. 因此,您需要在 tableView 数据源方法中将 FRC indexPaths 重新映射到 table 视图中的正确部分。所以在 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中使用错误的section).
我对实施 NSFetchedResultsController 感到困惑,因为我不断收到错误。我正在尝试将 Core Data 与 UITableView 连接起来,但我没有通过让 UITableView 根据 Core Data 中的记录数绘制出正确的行数来进入下一步。我收到此错误消息:
*** Terminating app
due to uncaught exception 'NSRangeException', reason: '***
[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
下面是我的代码:
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()
}
}
下面显示了包含 CoreDataStack 实现的文件:
import Foundation
import CoreData
class CoreDataStack {
private let modelName: String
init(modelName: String) {
self.modelName = modelName
}
lazy var managedContext: NSManagedObjectContext = {
return self.storeContainer.viewContext
}()
private lazy var storeContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: self.modelName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
print("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func saveContext() {
guard managedContext.hasChanges else { return }
do {
try managedContext.save()
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}
}
}
检查sqlite文件后,我确实使用liya确认了有名称记录的项目。对于任何有任何提示或想法的人,我将不胜感激。谢谢
问题是,在 FetchedResultsController 的视图中,只有一个部分:第 0 部分。但是您的 tableView 有两个部分,您希望 FRC 为部分提供数据1. 因此,您需要在 tableView 数据源方法中将 FRC indexPaths 重新映射到 table 视图中的正确部分。所以在 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中使用错误的section).