在TableView中,按日期对对象数组进行排序,并对它们进行相应的分段。

问题描述 投票:0回答:1

我有一个应用程序,其中包含允许用户上传一个餐点到firebase供以后查看,我想在TableView中以降序(按日期)显示这些餐点,并按它们被记录的日期和相应的部分进行排序。

餐点对象的定义如下

class Meal: NSObject, Codable {

var id: String?
var foodname: String?
var quantity: Float!
var brandName: String?
var quantityType: String?
var calories: Float!
var date: Date?
}

而我的TableView目前看起来是这样的

class MealsTableViewController: UITableViewController {

var databaseController: DatabaseProtocol?
var sections = Dictionary<String, Array<Meal>>()
var sortedSections = [String]()

var listOfMeals = [Meal]() {
    didSet {
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()


    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    databaseController = appDelegate.databaseController
    let accountsRef = databaseController?.getAccountsRef()

    accountsRef?.document(SingletonAccount.shared.userEmail).collection("meals")
        .getDocuments { (querySnapshot, error) in

            if error != nil {
                print("Error retrieving all meals!")
            }else{
                do{
                    for document in querySnapshot!.documents
                    {
                        let currentMeal = Meal()
                        let data = try! document.data()
                        currentMeal.id = data["id"] as? String ?? ""
                        currentMeal.brandName = data["brandName"] as? String ?? ""
                        currentMeal.calories = data["calories"] as? Float ?? 0.0
                        let parsingDate = data["date"] as! Timestamp
                        currentMeal.date = parsingDate.dateValue()
                        currentMeal.foodname = data["foodname"] as? String
                        currentMeal.quantity = data["quantity"] as? Float
                        currentMeal.quantityType = data["quantityType"] as? String
                        print(currentMeal.date)
                        self.listOfMeals.append(currentMeal)
                     }

                }catch{
                    print(error)
                }
            }
        }




}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return listOfMeals.count
}


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "foodCell", for: indexPath)
    cell.textLabel?.text = listOfMeals[indexPath.row].foodname
    cell.detailTextLabel?.text = String(listOfMeals[indexPath.row].calories) + "kJ"
    cell.detailTextLabel?.textColor = UIColor.secondaryLabel
    cell.accessoryType = .disclosureIndicator
    return cell
}

我也尝试使用下面的代码来尝试按日期对对象进行排序,但没有成功。

                self.listOfMeals.sort { (meal1, meal2) -> Bool in
                return (meal1.date!.compare(meal2.date!))
            }

我试过这里发布的其他方法,但似乎都不起作用。

swift firebase sorting uitableview tableview
1个回答
1
投票

我相信 compare 方法不是你所需要的,因为它将返回一个 比较结果 实例在这两个日期之间。另外,如果日期是选项,不要强行投掷,否则当其中一个日期为零时,你的应用程序可能会崩溃。

self.listOfMeals.sort { meal1, meal2 -> Bool in
    guard let meal1Date = meal1.date, let meal2Date = meal2.date else { return false }
    return meal1Date < meal2Date
}

0
投票

如果你想一次性对你的对象进行排序和分组,你可以使用 Dictionary(grouping:by:) 连同排序

let calendar = Calendar.current
let nilDate = Date.distantPast

let grouped = Dictionary(grouping: listOfMeals.sorted(by: { ($0.date ?? nilDate) < ($1.date ?? nilDate) }),
                         by: { calendar.startOfDay(for: $0.date ?? nilDate) })

下面是一个简单的测试案例

struct Meal: CustomStringConvertible {
    var id: String?
    var date: Date?

    var description: String {
        get {
            let dateString = date == nil ? "nil" : String(describing: date!)
            return "\(id!) \(dateString)"
        }
    }
}

let day = 24.0 * 60.0 * 60.0
var listOfMeals = [
    Meal(id: "a", date: Date(timeIntervalSinceNow: 5000)),
    Meal(id: "b", date: Date(timeIntervalSinceNow: -5000)),
    Meal(id: "c", date: Date(timeIntervalSinceNow: (day + 5000.0))),
    Meal(id: "d", date: Date(timeIntervalSinceNow: day)),
    Meal(id: "e", date: Date(timeIntervalSinceNow: -day)),
    Meal(id: "f", date: Date(timeIntervalSinceNow: -(day - 5000.0))),
    Meal(id: "g", date: Date(timeIntervalSinceNow: 0)),
    Meal(id: "h", date: Date(timeIntervalSinceNow: -2 * day)),
]

0
投票

我可能理解错了,但似乎这个问题是问如何读取按日期排序的膳食。

你不会想要像其他答案中显示的那样读取每顿饭菜,然后在内存中对它们进行排序,因为这可能是一个压倒性的数据量。所以请注意,您可以添加 极限 我的代码,以及只显示6月份的饭菜,或只有10餐的时间,例如。

让Firestore为你做这些工作。下面是读取你的饭菜对象降序的代码。

func readMealsSortedDesc() {
    let meals = self.db.collection("meals") //self.db points to my Firestore
    meals.order(by: "date", descending: true).getDocuments(completion: { snapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        guard let documents = snapshot?.documents else { return }

        for doc in documents {
            let docId = doc.documentID
            let name = doc.get("foodname") as? String ?? "No Food Name"
            let date = doc.get("date") as? Timestamp ?? Timestamp()
            print(docId, name, date.dateValue())
        }
    })
}

如果6月有三顿饭(只为6月增加了一个限制),1号一顿,15号一顿,30号一顿,下面是输出结果。

meal_2 Hot Dog 2020-06-30 04:00:00 +0000
meal_1 Burger 2020-06-15 04:00:00 +0000
meal_0 Pizza 2020-06-01 04:00:00 +0000

我不知道你具体想如何组织数据,但你应该有一个dataSource数组,它包含了代表各部分的对象,也包含了部分子数据。像这样

var myDailyMealsArray = [DailyMealStruct]()

struct DailyMealStruct {
    var sectionTitle = "this would be a string of the date"
    var mealNameArray = [String]()
}

因此,当你的数据从Firebase读取时,将其添加到相应的DailyMealStruct对象中(该对象中包含2020-06-01的所有膳食,然后该对象中包含2020-06-02的所有膳食等)。

从那里,你的部分是myDailyMealsArray中的#个对象,而子数据则来自每个对象内的 mealNameArray。

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

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    let title = self.myDailyMealsArray[section].sectionTitle
    return title
}
© www.soinside.com 2019 - 2024. All rights reserved.