UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接

Posted

技术标签:

【中文标题】UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接【英文标题】:UITableView with Multiple Sections in Alphabetical Order using Realm and Swift, with multiple labels connected with same data 【发布时间】:2019-12-21 18:43:35 【问题描述】:

现在已经尝试解决这个问题超过 10 天了,但仍然没有任何运气来解决这个问题。

我正在尝试根据“ExerciseName”列的名称按字母顺序从 A-Z 将部分添加到表视图中。我还有一个“BodyPartName”、“CategoryName”?每个“练习名称”的数据列。

我想从 A-Z 填充各个部分,并将 ExerciseName 排序到每个部分,其中 BodyPartName 和 CategoryName 用于同一行中的其他标签。

我在 A-Z 部分下成功实施了 ExerciseName,但无法将 BodyPartName 和 CategoryName 添加到同一行的其他标签中。请帮忙!!

预期结果

一个

Abs“(核心)”

手臂推举“(手臂)”“(哑铃)”

B

二头肌卷曲“(手臂)”“(杠铃)”

后扩展“(返回)”“(机器)”

无法为同一行填充“BodyPartName”标签和“CategoryName”标签。

这是我的领域数据模型:

class Exercises: Object


    @objc dynamic var ExerciseID = 0
    @objc dynamic var ExerciseName = ""
    @objc dynamic var BodyPartName = ""
    @objc dynamic var CategoryName: String? = ""

    //Adding Parent Table BodyPart & Category.
    var parentBodyParts = LinkingObjects(fromType: BodyParts.self, property: "exercises")
    var parentCategory = LinkingObjects(fromType: Category.self, property: "category")


我的代码:

let realm = try! Realm()
var exerciseArray: Results<Exercises>!

override func viewDidLoad()
    
        super.viewDidLoad()
        tableView.register(UINib(nibName: "customCell", bundle: nil), forCellReuseIdentifier: cellID)
        sectionFunction()
    

var sectionDictionary = [String:[String]]()
var sectionTitles = [String]()

func sectionFunction()

     exerciseArray = realm.objects(Exercises.self).sorted(byKeyPath: "ExerciseName")

    for section in exerciseArray
    
        let sectionKey = String(section.ExerciseName.prefix(1)) 

        if var sectionValues = sectionDictionary[sectionKey]
        
            sectionValues.append(section.ExerciseName) // Adding ExerciseNames to the Keys
            sectionDictionary[sectionKey] = sectionValues
        
        else
        
            sectionDictionary[sectionKey] = [section.ExerciseName]
        
    
    sectionTitles = [String](sectionDictionary.keys)
    sectionTitles = sectionTitles.sorted(by: $0 < $1) // Alphabetical order for Keys:Values


override func numberOfSections(in tableView: UITableView) -> Int
    
        return sectionTitles.count
    


    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
    
        return sectionTitles[section]
    


    override func sectionIndexTitles(for tableView: UITableView) -> [String]?
    
        return sectionTitles
    


    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    
        let sectionKey = sectionTitles[section]
        if let sectionValues = sectionDictionary[sectionKey]
        
            return sectionValues.count
        
        return 0
       // return exercises.filter("ExerciseName == %@", sectionNames[section]).count
    

    // Register custom cell for Table View
    let cellID = "customCell"

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    
      let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! customCell

        let sectionKey = sectionTitles[indexPath.section]
        if let sectionValues = sectionDictionary[sectionKey]
        
          exerciseArray = realm.objects(Exercises.self).sorted(byKeyPath: "ExerciseName")

            cell.exerciseName.text = sectionValues[indexPath.row]
            cell.bodyPartName.text = exerciseArray.filter("ExerciseName == %@", sectionValues[indexPath.row]) [indexPath.row].BodyPartName
            cell.categoryName.text = exerciseArray.filter("ExerciseName == %@", sectionValues[indexPath.row])  [indexPath.row].CategoryName ?? ""
            cell.backgroundColor = .clear
        
        return cell
    

自定义单元格:

class customCell: UITableViewCell 

    @IBOutlet weak var exerciseName: UILabel!
    @IBOutlet weak var bodyPartName: UILabel!
    @IBOutlet weak var categoryName: UILabel!

    override func awakeFromNib() 
        super.awakeFromNib()
    

override func setSelected(_ selected: Bool, animated: Bool) 
    super.setSelected(selected, animated: animated)   
   

【问题讨论】:

无需过多研究代码即可。有评论 Register custom cell for Table View 但下面的代码没有这样做;它只设置了一个类级别的cellID string。您应该在 viewDidLoad 中加载自定义单元格 nib 并将其注册到您的 tableView,类似于self.myTableView.register(myNib, forIdentifier: cellIdentifier),这也将避免在cellForRowAt 中重复执行此操作。其次,cellForRowAt 中的代码应该最少,以确保响应式 UI。所以这个let exerciseList = realm.objects(Exercises.self) 应该在别处。 ...您应该为您的 tableView 数据利用 tableView 数据源,这是您的 tableView 项目的预加载“列表”,并从该列表中提取数据,不要点击每次您需要 cellview 的数据时使用磁盘。互联网上有许多关于使用 UITableViews 的很棒的教程,您可能想看看。 感谢您的回复@Jay,我尝试将代码添加到 viewdidload: self.tableView.register(customCell.self, forCellReuseIdentifier: "customCell") //.register(myNib, forIdentifier: cellIdentifier ) 但它返回一个空的 tableview。 @Jay,但没有任何改变可以解决我的问题。仍然用练习名称填充我的部分,但不是 bodypartName 和 categoryName 该代码存在许多问题 - 在 cmets 中无法真正解决,但例如,此 cell.bodyPartName.text = exerciseArray.filter("ExerciseName == %@", sectionValues[indexPath.row]) [indexPath.row].BodyPartName 是个坏主意。您不想在尝试填充 tableView 时进行过滤。 【参考方案1】:

问题中的代码存在许多问题,我不尝试剖析它们,而是提供一个可能有帮助的示例。

假设我们有一堆水果存储在 Realm 中。我们希望使用部分在 tableview 中按字母顺序显示它们

A
   Apple
B
   Banana

第一段代码是一个结构,用于保存部分标题,然后是该部分中的水果数组。还有一个类fruitNameArray,它将充当我们的tableView DataSource,它包含所有FruitStructs。

struct FruitStruct 
    var sectionTitle = ""
    var fruitNameArray = [String]()


var fruitDataSource = [FruitStruct]()

我使用数组来保存初始数据,但在您的情况下,它可能是从领域填充的领域结果对象。这是从 viewDidLoad 中调用的,用于将我们的数据组织到 dataSource 数组中

func setupDataSourceData() 
    let fruitArray = ["Apple", "Pear", "Banana", "Bing Cherry", "Grape", "Orange", "Plum", "Watermelon", "Cantelope"]

    let allFirstChars = fruitArray.map  String($0.prefix(1))  //get all first chars for section titles
    let sectionTitles = Array(Set(allFirstChars)).sorted() //eliminate dups and sort

    //iterate over the unique section titles and get the fruits that are in that section
    // sort and then craft structs to hold the title and the associated fruits
    sectionTitles.forEach  firstChar in
        let results = fruitArray.filter  $0.prefix(1) == firstChar 
        let sortedFruits = results.sorted()
        let fruit = FruitStruct(sectionTitle: firstChar, fruitNameArray: sortedFruits)
        fruitDataSource.append(fruit)
    

    for fruitData in fruitDataSource 
        print(fruitData.sectionTitle)
        let fruits = fruitData.fruitNameArray
        for fruitName in fruits 
            print("  \(fruitName)")
        
    

然后,tableView 需要 4 个函数来显示节,然后显示每个节中的行。您似乎拥有这 4 个,但还有一个可能不需要的 sectionIndexTitles

//
//handle sections
//
func numberOfSections(in tableView: UITableView) -> Int 
    return self.fruitDataSource.count


func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 
    let title = self.fruitDataSource[section].sectionTitle
    return title


//
//handleTableView rows
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    let rowsInSection = self.fruitDataSource[section].fruitNameArray.count
    return rowsInSection


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier", for: indexPath)
    let text = self.fruitDataSource[indexPath.section].fruitNameArray[indexPath.row]
    cell.textLabel?.text = text
    return cell

请注意,在填充 tableView 时,我没有执行任何过滤和任何其他操作。这部分代码需要快速且精简到 UI 尽可能响应。

我只是得到一个字符串

let text = self.fruitDataSource[indexPath.section].fruitNameArray[indexPath.row]

但在您的情况下,您可能希望返回一个 exersise 对象,然后您可以在其中获取 exerciseName 和 bodypartName,然后在自定义 cellView 中分配它们

最佳实践说明:类属性应小写 - 练习名称,而不是大写,练习名称。类和结构名称通常大写。

【讨论】:

以上是关于UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接

什么时候/如何排序Realm孩子 Swift中UITableView的属性

如何在Swift中返回Realm列表?

UITableView 在 segmentedControlChanged 上没有改变

设置UITableView数据源并在单独的文件中委托 - swift

UITableView Checkmarks 在错误的地方搜索后