使用 Realm 和 Swift 查询 Realm 以使用多个部分填充 numberOfRowsInSection 和 cellForRowAt

Querying Realm to populate numberOfRowsInSection and cellForRowAt with Multiple Sections using Realm and Swift

我是 Realm 和 Swift 的新手,也是这个网站的新手,所以如果我的问题措辞不当,请原谅我,但我会尽力而为。开始了...

基本上我正在尝试构建一个健身房应用程序。这个想法是允许用户输入他们锻炼的标题,并从选择器视图中输入 select 一周中的某一天,以分配给该特定锻炼。

话虽如此,我在弄清楚如何编写 numberOfRowsInSection 函数的代码时遇到了一些问题,以便它 return 根据该特定部分中的 objects 行数.换句话说,return 行数基于我为一周中的特定一天存储的锻炼次数。

我也遇到了与 cellForRowAt 函数类似的问题。我试图弄清楚如何根据一周的 section/day 用锻炼的标题填充单元格。

如有任何帮助,我们将不胜感激。

import UIKit
import RealmSwift
import SwipeCellKit

class WorkoutsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SwipeTableViewCellDelegate {


    let realm = try! Realm()

    var workouts : Results<Workouts>?
    var days : Results<WeekDays>?

    var daysOfWeek : [String] = ["Monday", "Tuesday", "Wednsday", "Thursday", "Friday", "Saturday", "Sunday"]

    let picker = UIPickerView()


    @IBOutlet weak var WorkoutsTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        WorkoutsTableView.delegate = self
        WorkoutsTableView.dataSource = self

        picker.delegate = self
        picker.dataSource = self

        loadCategories()
    }


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        tableView.rowHeight = 80.0

        //Populate based on the # of workouts in each day.

        return 0
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let button = UIButton(type: .system)
        button.setTitleColor(.black, for: .normal)
        button.backgroundColor = .lightGray
        button.setTitle(daysOfWeek[section], for: .normal)

        return button
    }


    func numberOfSections(in tableView: UITableView) -> Int {
        return 7
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SwipeTableViewCell
        cell.accessoryType = .disclosureIndicator
        cell.delegate = self

        //Populate with titles of workouts based on section/day of the week.
        //cell.textLabel?.text = days?[indexPath.row].workouts[indexPath.row].name


        return cell
    }

    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {

        guard orientation == .right else { return nil }

        let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in



        }

        // customize the action appearance
        deleteAction.image = UIImage(named: "delete-icon")

        return [deleteAction]
    }

    func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
        var options = SwipeOptions()
        options.expansionStyle = .destructive
        return options
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }



    @IBAction func AddWorkoutButton(_ sender: UIButton) {
        var textField = UITextField()

        let alert = UIAlertController(title: "New Workout", message: "Please name your workout...", preferredStyle: .alert)

        let addAction = UIAlertAction(title: "Add Workout", style: .default) { (UIAlertAction) in
                //Add workout to database
            let newWorkout = Workouts()
            let dow = WeekDays()

            dow.day = self.daysOfWeek[self.picker.selectedRow(inComponent: 0)]
            newWorkout.name = textField.text!
            dow.workouts.append(newWorkout)

            self.save(newDay: dow)
        }

        alert.addTextField { (alertTextField) in
            alertTextField.placeholder = "Muscle Group"
            textField = alertTextField
            alertTextField.inputView = self.picker
        }

        alert.addAction(addAction)

        present(alert, animated: true, completion: nil)
    }

    func save(newDay: WeekDays){
        do {
            try realm.write {
                realm.add(newDay)
            }
        } catch {
            print("Error saving workout \(error)")
        }
        WorkoutsTableView.reloadData()
    }

    func loadCategories(){
        days = realm.objects(WeekDays.self)
        workouts = realm.objects(Workouts.self)
        WorkoutsTableView.reloadData()
    }

    @IBAction func EditWorkout(_ sender: UIBarButtonItem) {

    }

}

extension WorkoutsViewController : UIPickerViewDelegate, UIPickerViewDataSource {

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return 7
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

        return daysOfWeek[row]
    }



}

{

class Workouts : Object {
            @objc dynamic var name : String = ""
            var parentDay = LinkingObjects(fromType: WeekDays.self, property: "workouts")
        }




class WeekDays : Object {
    @objc dynamic var day : String = ""
    let workouts = List<Workouts>()
}

感谢您为我们提供您的模型。如我所见,您的 WeekDay 元素上已经有一个 Workouts 列表,因此您填充 Table 视图的查询由此得到简化。

要事第一。我建议您更改控制器中的结果声明以使用以下内容

class WorkoutsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SwipeTableViewCellDelegate {
    let realm = try! Realm()
    var days : Results<WeekDays>!
    // ... rest of the implementation 
}

这样您就可以取消对 table 视图数据源和委托方法的可选处理。

也就是说,您只需要查询视图控制器上的 WeekDay 个对象。我通常在 viewDidLoad:

上这样做
days = realm.objects(WeekDays.self)

关联的 workouts 会自动加载并关联到您从数据库中获取的每一天,在 days 数组中。

根据您的要求,您可以为 table 视图创建所需数量的部分,如下所示:

func numberOfSections(in tableView: UITableView) -> Int {
    return self.days.count
}

该代码将创建与 days 数组大小一样多的部分。下一个任务是提供给定部分中的行数。这几乎是立竿见影的,因为我们当天已经有了 WorkOuts 个对象的数组:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let day = days[section]
    return day.workouts.count
}

此时我们已经在 table 视图中提供了部分的数量(天)和每个部分的行数(与相应日期相关的锻炼)。

在此之后,可以根据 days 数组信息配置每个单元格(不要忘记这是一个 WeekDays 对象数组,每个对象包含一个 workouts 数组.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SwipeTableViewCell
    cell.accessoryType = .disclosureIndicator
    cell.delegate = self

    // Populate with titles of workouts based on section/day of the week.
    cell.textLabel?.text = days[indexPath.section].workouts[indexPath.row].name

    return cell
}

这里的关键是您必须获取 WeekDays 对象(通过从 days 数组获取索引 indexPath.section 处的对象),然后通过获取Workouts 工作日数组中索引 indexPath.row 处的对象。

希望对您有所帮助!