fetchedResultsController 对象的表视图部分
Posted
技术标签:
【中文标题】fetchedResultsController 对象的表视图部分【英文标题】:Table View sections for fetchedResultsController objects 【发布时间】:2020-09-24 17:41:47 【问题描述】:我正在尝试为我的 tableView 数据编制索引,并按姓名首字母对列出的人员的姓名进行排序。我已经看过很多关于使用 genericall 非持久数据的教程,但没有使用 Core Data 和使用 fetchedResultsController 选项(用于 iCloud 自动同步)。
现在我的代码如下(为了清楚起见,我只转录与问题相关的部分):
//The two arrays to populate from Core Data, used later to populate the table
var alumnosDictionaryArray = [String:[String]]()
var titulosSeccionArray = [String]()
override func viewDidLoad()
super.viewDidLoad()
//Obtain data from Core Data
updateFetchedResultsController()
//Populate the arrays with this data
populateArrays()
func updateFetchedResultsController()
guard let context = container?.viewContext else return
context.performAndWait
let sortDescriptor = NSSortDescriptor(key: "nombre", ascending: true)
request.sortDescriptors = [sortDescriptor]
fetchedResultsController = NSFetchedResultsController<Alumno>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
do
try fetchedResultsController?.performFetch()
tableView.reloadData()
catch
print("Error obtaining data: \(error)")
func populateArrays()
if let objects = fetchedResultsController?.fetchedObjects
for alumno in objects
let inicial = String(alumno.nombre?.prefix(1) ?? "")
if var values = alumnosDictionaryArray[inicial]
values.append(alumno.nombre!)
alumnosDictionaryArray[inicial] = values
else
alumnosDictionaryArray[inicial] = [alumno.nombre!]
titulosSeccionArray = [String](alumnosDictionaryArray.keys)
titulosSeccionArray = titulosSeccionArray.sorted(by: $0 < $1)
这部分似乎工作正常,因为数组已正确填充,正如我已检查打印语句一样。
稍后,对于表格数据:
override func numberOfSections(in tableView: UITableView) -> Int
return titulosSeccionArray.count
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
let inicial = titulosSeccionArray[section]
if let values = alumnosDictionaryArray[inicial]
return values.count
return 0
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! AlumnoCell
if self.validateIndexPath(indexPath)
let object = fetchedResultsController?.object(at: indexPath)
let inicial = titulosSeccionArray[indexPath.section]
if let values = alumnosDictionaryArray[inicial]
cell.nombreField.text = values[indexPath.section]
cell.especialidadField.text = object?.especialidadRelacionada?.nombre
cell.cursoField.text = object?.cursoRelacionado?.nivel
cell.tutorField.text = object?.tutorRelacionado?.nombre
else
print("Error from indexPath")
return cell
//To validate indexPath
func validateIndexPath(_ indexPath: IndexPath) -> Bool
if let sections = self.fetchedResultsController?.sections,
indexPath.section < sections.count
if indexPath.row < sections[indexPath.section].numberOfObjects
return true
return false
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
return titulosSeccionArray[section]
我得到了一个或多或少完整的表格,其中包含正确的部分、部分的标题(首字母)以及每个部分的行数,但似乎只有第一行有效,因为其余数据为空并抛出选择任何时出错:“索引 1 处没有部分”。事实上,在抛出异常之前,我在控制台上收到了许多“来自 indexPath 的错误”消息......
有什么建议吗?谢谢。
【问题讨论】:
我相信如果您使用 NSFetchedResultsController 内置的部分功能而不是尝试使用您自己的数组来做这件事,这会更容易。完成此操作后,我将“部分”字段放入对象中,然后在获取时将其用作部分键路径。这样,表格视图可以直接从结果中填充。 谢谢。你能不能给我一个更详细的例子。我从swift开始,并不清楚你的想法。 【参考方案1】:对于 Alumno
实体,再添加 1 列 nombreFirstChar
。
然后使用类似这样的东西将这个变量保存在数据库中:
alumno.nombreFirstChar = nombre.firstCharacter()
这里firstCharacter
的辅助方法会是这样的:
func firstCharacter() -> String
var firstCharacter = self.first ?? "#"
if (!(firstCharacter >= "a" && firstCharacter <= "z") && !(firstCharacter >= "A" && firstCharacter <= "Z") )
firstCharacter = "#"
return String(firstCharacter).capitalized
现在在您的 fetchedResultsController 中,替换这一行
fetchedResultsController = NSFetchedResultsController<Alumno>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
与
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "nombreFirstChar", ascending: true)]
fetchRequest.propertiesToGroupBy = ["nombreFirstChar"]
fetchedResultsController = NSFetchedResultsController<Alumno>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nombreFirstChar, cacheName: nil)
然后在table view delegate apis中,你可以像这样使用fetchedResultsController:
func numberOfSections(in tableView: UITableView) -> Int
return fetchedResultsController.sections?.count ?? 0
func sectionIndexTitles(for tableView: UITableView) -> [String]?
guard let fetchedResultsSections: [NSFetchedResultsSectionInfo] = channelFetchedResultsController.sections else return nil
return fetchedResultsSections!.mapString($0.name)
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
guard var fetchedResultsSections: [NSFetchedResultsSectionInfo] = fetchedResultsController.sections else return nil
return fetchedResultsSections[section].name
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
guard var sections:[NSFetchedResultsSectionInfo] = fetchedResultsController.sections, let section = sections[section] else
return 0
return section.numberOfObjects
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
cell.accessoryType = .disclosureIndicator
let alumno = fetchedResultsController.object(at: indexPath)
...
return cell
【讨论】:
以上是关于fetchedResultsController 对象的表视图部分的主要内容,如果未能解决你的问题,请参考以下文章
FetchedResultsController 中没有部分
如何将对象从 fetchedResultsController 到 Plist?
fetchedResultsController 对象的表视图部分
fetchedResultsController 和 Integer