我正在构建一个涉及相当复杂的表视图的辅助项目。我决定从Producthunt的应用程序中获取灵感,每个日期都有一个标题部分。 但是唉,这个简单的实现比我想象的要难一点。作为参考,我在下面附上照片,向您展示我正在尝试克隆的内容。这是来自PH的应用程序:
看看顶部有一个今天和昨天标题部分,旁边有日期寒冷吗?我问过同行,其中一些建议尝试[[array]](数组内部的数组)方法。通过枚举将它们分组并将它们放入特定的数组中吗?这很好,但过了一段时间,你可以看到它失控。例如,下面是我的一些代码:
enum dateCases {
case today
case yesterday
case twoDaysAgo
case threeDaysAgo
case fourDaysAgo
case fiveDaysAgo
case lastWeek
case lastMonth
case lastYear
case janurary
case feburary
case march
case april
case may
case june
case july
case augest
case september
case october
case november
case december
}
struct dateCaseController {
var todayArray = [Objects]()
var yesterdayArray = [Objects]()
var twoDaysAgoArray = [Objects]()
var threeDaysAgoArray = [Objects]()
var fourDaysAgoArray = [Objects]()
var fiveDaysAgoArray = [Objects]()
var lastWeekArray = [Objects]()
var lastMonthArray = [Objects]()
var lastYearArray = [Objects]()
var januraryArray = [Objects]()
var feburaryArray = [Objects]()
var marchArray = [Objects]()
var aprilArray = [Objects]()
var mayArray = [Objects]()
var juneArray = [Objects]()
var julyArray = [Objects]()
var augestArray = [Objects]()
var septemberArray = [Objects]()
var octoberArray = [Objects]()
var novemberArray = [Objects]()
var decemberArray = [Objects]()
}
对象都有日期,我们可以使用它来分析和分割数据。这个类的每个实例都有这个结构。
func anilyzeDateForDateCase(){
for object in objects {
let dateValue = (Logic for counting how many days has passed)
switch dateValue {
case 0:
print("")
case 1:
print("")
case 2:
print("")
case 3:
print("")
case 4:
print("")
case 5:
print("")
case 6:
print("")
ect.....
这将是很多切换案例。你可以通过这种方法来判断代码是否会失控。如果我有少量类别,使用这种方法会很好,但事实并非如此。更不用说在那之后,我将根据部分加载表数组。我这样做很好,但我想知道这是否是解决这个问题的正确方法?必须有一个更简单的解决方案。有没有人有这样的实现经验?谢谢。
答案 0 :(得分:3)
正如您正确推断的那样,enum
不是的方式。除了其他任何东西,它都是将UI选择硬编码到您的数据结构中。
我可以提出以下建议吗:
import Foundation
// Define a `struct` that describes a date range.
// You may want to have convenience inits that don't just specify "days ago".
// You will create an array of these later...
struct DateRange {
var latestDaysAgo: Int
var earliestDaysAgo: Int
var description: String
// The important piece of this is that we can check if any given date
// is in `self` - we will use this later to `filter` by DateRange
func isDateInRange(_ date: Date) -> Bool {
let now = Date()
let oneDayInSeconds = 86400.0 // 60 * 60 * 24
let earliestDate = now.addingTimeInterval(Double(-self.earliestDaysAgo) * oneDayInSeconds)
let latestDate = now.addingTimeInterval(Double(-self.latestDaysAgo) * oneDayInSeconds)
return (date > earliestDate) && (date <= latestDate)
// NB - you REALLY want to do this with `Calendar` arithmetic
// but for clarity of the method, I'm just using 24 hour time differences
}
}
// Now construct your ranges. These can be extended after testing.
// They can also be overlapping.
let ranges: [DateRange] = [
DateRange(latestDaysAgo: 0, earliestDaysAgo: 1, description: "Today"),
DateRange(latestDaysAgo: 1, earliestDaysAgo: 2, description: "Yesterday"),
DateRange(latestDaysAgo: 2, earliestDaysAgo: Int.max, description: "Earlier"),
]
// This is whatever event struct you need - but they include the date
struct Event {
var date: Date
var payload: String // or whatever struct you want
}
// Create some random test data
let events: [Event] = [
Event(date: Date().addingTimeInterval(-100), payload: "abc"),
Event(date: Date().addingTimeInterval(-1000), payload: "abc"),
Event(date: Date().addingTimeInterval(-100000), payload: "abc"),
Event(date: Date().addingTimeInterval(-1000000), payload: "abc"),
]
// Now, the clever piece is combining `flatMap` & `filter` to get your sections:
let sections: [(DateRange, [Event])] = ranges.flatMap({
(dr: DateRange) in
let qualifyingEvents = events.filter({ dr.isDateInRange($0.date) })
return (dr, qualifyingEvents)
})
// Note that the order of ranges in `sections` is the same as the
// order that you chose in `ranges`.
// Check the sections are correct.
for (dr, es) in sections {
print("'\(dr.description)' has \(es.count) entries")
}
/* Output:
'Today' has 2 entries
'Yesterday' has 1 entries
'Earlier' has 1 entries
*/
您现在可以使用UITableViewDataSource
驾驶sections
。例如:
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].1.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].0.description
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "MyCellID")
let payload = sections[indexPath.section].1[indexPath.row].payload
cell.textLabel?.text = payload // or whatever...
return cell
}