首页 > 解决方案 > 使用 Realm 和 Swift 查询领域以使用多个部分填充 numberOfRowsInSection 和 cellForRowAt

问题描述

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

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

话虽如此,我在弄清楚如何对 numberOfRowsInSection 函数进行编码以便它根据该特定部分中的对象数返回行数时遇到了一些麻烦。换句话说,根据我为一周中的特定日期存储的锻炼次数返回行数。

我对 cellForRowAt 函数也有类似的问题。我试图弄清楚如何根据一周中的部分/日期,用锻炼的标题填充单元格。

任何帮助将不胜感激。

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>()
}

标签: swiftuitableviewrealm

解决方案


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

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

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

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

话虽如此,您只需要查询WeekDay视图控制器上的对象。我通常在viewDidLoad

days = realm.objects(WeekDays.self)

关联workouts的会自动加载,并与您从数据库中获取的每一天相关联,在days阵列上。

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

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
}

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

在此之后,每个单元格都可以根据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对象(通过indexPath.section从数组的索引处获取对象),然后通过从工作日的数组中获取索引处的对象days来获取锻炼详细信息。WorkoutsindexPath.row

希望这可以帮助!


推荐阅读