fetchedResultsController对象的“表视图”部分

问题描述

我正在尝试为tableView数据建立索引,并按其姓名首字母对所列出人员的姓名进行排序。我看过很多关于使用通用的所有非持久数据执行此操作的教程,但是没有关于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的错误”消息。

有什么建议吗?谢谢。

解决方法

对于Alumno实体,再增加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,sectionNameKeyPath: nombreFirstChar,cacheName: nil)

然后在表视图委托api中,可以像这样使用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!.map{String($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
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...