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

UITableView with Multiple Sections in Alphabetical Order using Realm and Swift, with multiple labels connected with same data

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

我正在尝试根据 "ExerciseName" 列的名称从 A-Z 的字母顺序向 table 视图添加部分。我还有一个"BodyPartName"、"CategoryName"?每个 "ExerciseName" 的数据列。

我想从 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: {[=12=] < }) // 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)   
}   

}

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

假设我们有一堆水果存储在 Realm 中。我们想使用 sections

在 tableview 中按字母顺序显示这些内容
A
   Apple
B
   Banana

等等

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

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

var fruitDataSource = [FruitStruct]()

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

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

    let allFirstChars = fruitArray.map { String([=12=].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 { [=12=].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]

但在您的情况下,您可能想要 return 锻炼 object 然后您可以在其中获取 exerciseName 和 bodypartName,然后在自定义 cellView

中分配它们

最佳实践注意事项:class 属性应小写 - exerciseName,而不是大写,ExerciseName。 Class 和结构名称通常大写。