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的属性
UITableView 在 segmentedControlChanged 上没有改变