为时间段构建数据模型
Constructing a data model for Time Periods
我正在构建一个应用程序,提供类似于遛狗的服务。遛狗的人可以上传可以遛狗的日期和时间。我没有让他们选择像 1 月 1 日星期一这样的实际日期,而是让他们选择一周中的任何几天以及他们有空的任何时间。
我遇到的问题是我不知道如何为它构建数据模型。
照片中的是一个带有单元格的 collectionView,在每个单元格中我都显示了他们可以选择的可用日期和时间段。一周中的每一天都有相同的 7 个时间段,想要成为遛狗者的用户可以从中选择。
问题是,如果有人选择 Sun 6am-9am、12pm-3pm 和 6pm-9pm,但他们也选择 Mon 6am-9m,我如何构建可以区分日期和时间的数据模型。例如星期天早上 6 点到 9 点和星期一早上 6 点到 9 点,如何区分?这些时间段应该是双打还是字符串?
这是我目前用于 collectionView 数据源和单元格的内容:
// the collectionView's data source
var tableData = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
//cellForItem
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: availabilityCell, for: indexPath) as! AvailabilityCell
cell.clearCellForReuse()
cell.dayOfWeek = tableData[indexPath.item]
// inside the AvailabilityCell itself
var dayOfWeek: String? {
didSet {
dayOfWeekLabel.text = dayOfWeek
}
}
func clearCellForReuse() {
dayOfWeekLabel.text = nil
// deselect whatever radio buttons were selected to prevent scrolling issues
}
进一步解释一下最终会发生什么,当想要遛狗的用户滚动查看谁有空时,如果他们滚动的日期和时间不在该人的任何日期和时间上谁 posted(周日和周一,选择的时间)不可用,那么他们的 post 不应该出现在提要中,但如果是那些日子之一和那些时间之一,那么他们的post 将出现在提要中(在示例中,如果某人在周日晚上 10 点滚动,则不应出现此 post)。数据模型中的任何内容都将与 post 当前滚动的任何日期和时间进行比较。我在后端使用 Firebase。
我想出的东西相当复杂,这就是为什么我需要更合理的东西。
class Availability {
var monday: String?
var tuesday: String?
var wednesday: String?
var thursday: String?
var friday: String?
var saturday: String?
var sunday: String?
var slotOne: Double? // sunday 6am-9am I was thinking about putting military hours here that's why I used a double
var slotTwo: Double? // sunday 9am-12pm
var slotTwo: Double? // sunday 12pm-3pm
// these slots would continue all through saturday and this doesn't seem like the correct way to do this. There would be 49 slots in total (7 days of the week * 7 different slots per day)
}
我也考虑过将它们分成不同的数据模型,例如星期一 class、星期二 class 等,但这似乎也行不通,因为它们都必须是相同的数据collectionView 数据源的类型。
更新
在@rob 的回答中,他给了我一些见解,让我可以对我的代码进行一些更改。我还在消化它,但我仍然有几个问题。他做了一个cool project that shows his idea.
1- 由于我将数据保存到 Firebase 数据库,数据应该如何结构化才能保存?可以有多个时间相似的日子。
2- 我仍然在思考 rob 的代码,因为我以前从未处理过时间范围,所以这对我来说很陌生。我仍然不知道要根据什么进行排序,尤其是回调内部的时间范围
// someone is looking for a dog walker on Sunday at 10pm so the initial user who posted their post shouldn't appear in the feed
let postsRef = Database().database.reference().child("posts")
postsRef.observe( .value, with: { (snapshot) in
guard let availabilityDict = snapshot.value as? [String: Any] else { return }
let availability = Availability(dictionary: availabilityDict)
let currentDayOfWeek = dayOfTheWeek()
// using rob;s code this compares the days and it 100% works
if currentDayOfWeek != availability.dayOfWeek.text {
// don't add this post to the array
return
}
let currentTime = Calendar.current.dateComponents([.hour,.minute,.second], from: Date())
// how to compare the time slots to the current time?
if currentTime != availability.??? {
// don't add this post to the array
return
}
// if it makes this far then the day and the time slots match up to append it to the array to get scrolled
})
func dayOfTheWeek() -> String? {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEEE"
return dateFormatter.stringFromDate(self)
}
猫皮有很多方法,但我可能会将可用性定义为日期枚举和时间范围:
struct Availability {
let dayOfWeek: DayOfWeek
let timeRange: TimeRange
}
你的星期几可能是:
enum DayOfWeek: String, CaseIterable {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
或者你也可以这样做:
enum DayOfWeek: Int, CaseIterable {
case sunday = 0, monday, tuesday, wednesday, thursday, friday, saturday
}
它们是 Int
和 String
的优缺点。在基于 Web 的 Firestore UI 中,字符串表示形式更易于阅读。整数表示提供了更容易的排序潜力。
您的时间范围:
typealias Time = Double
typealias TimeRange = Range<Time>
extension TimeRange {
static let allCases: [TimeRange] = [
6 ..< 9,
9 ..< 12,
12 ..< 15,
15 ..< 18,
18 ..< 21,
21 ..< 24,
24 ..< 30
]
}
在与 Firebase 交互方面,它不理解枚举和范围,所以我定义了一个 init
方法和 dictionary
属性 来映射到 [String: Any]
可以与 Firebase 交换的词典:
struct Availability {
let dayOfWeek: DayOfWeek
let timeRange: TimeRange
init(dayOfWeek: DayOfWeek, timeRange: TimeRange) {
self.dayOfWeek = dayOfWeek
self.timeRange = timeRange
}
init?(dictionary: [String: Any]) {
guard
let dayOfWeekRaw = dictionary["dayOfWeek"] as? DayOfWeek.RawValue,
let dayOfWeek = DayOfWeek(rawValue: dayOfWeekRaw),
let startTime = dictionary["startTime"] as? Double,
let endTime = dictionary["endTime"] as? Double
else {
return nil
}
self.dayOfWeek = dayOfWeek
self.timeRange = startTime ..< endTime
}
var dictionary: [String: Any] {
return [
"dayOfWeek": dayOfWeek.rawValue,
"startTime": timeRange.lowerBound,
"endTime": timeRange.upperBound
]
}
}
您还可以定义一些扩展以使其更易于使用,例如,
extension Availability {
func overlaps(_ availability: Availability) -> Bool {
return dayOfWeek == availability.dayOfWeek && timeRange.overlaps(availability.timeRange)
}
}
extension TimeRange {
private func string(forHour hour: Int) -> String {
switch hour % 24 {
case 0: return NSLocalizedString("Midnight", comment: "Hour text")
case 1...11: return "\(hour % 12)" + NSLocalizedString("am", comment: "Hour text")
case 12: return NSLocalizedString("Noon", comment: "Hour text")
default: return "\(hour % 12)" + NSLocalizedString("pm", comment: "Hour text")
}
}
var text: String {
return string(forHour: Int(lowerBound)) + "-" + string(forHour: Int(upperBound))
}
}
extension DayOfWeek {
var text: String {
switch self {
case .sunday: return NSLocalizedString("Sunday", comment: "DayOfWeek text")
case .monday: return NSLocalizedString("Monday", comment: "DayOfWeek text")
case .tuesday: return NSLocalizedString("Tuesday", comment: "DayOfWeek text")
case .wednesday: return NSLocalizedString("Wednesday", comment: "DayOfWeek text")
case .thursday: return NSLocalizedString("Thursday", comment: "DayOfWeek text")
case .friday: return NSLocalizedString("Friday", comment: "DayOfWeek text")
case .saturday: return NSLocalizedString("Saturday", comment: "DayOfWeek text")
}
}
}
如果你不想使用Range
,你可以将TimeRange
定义为struct
:
enum DayOfWeek: String, CaseIterable {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
extension DayOfWeek {
var text: String {
switch self {
case .sunday: return NSLocalizedString("Sunday", comment: "DayOfWeek text")
case .monday: return NSLocalizedString("Monday", comment: "DayOfWeek text")
case .tuesday: return NSLocalizedString("Tuesday", comment: "DayOfWeek text")
case .wednesday: return NSLocalizedString("Wednesday", comment: "DayOfWeek text")
case .thursday: return NSLocalizedString("Thursday", comment: "DayOfWeek text")
case .friday: return NSLocalizedString("Friday", comment: "DayOfWeek text")
case .saturday: return NSLocalizedString("Saturday", comment: "DayOfWeek text")
}
}
}
struct TimeRange {
typealias Time = Double
let startTime: Time
let endTime: Time
}
extension TimeRange {
static let allCases: [TimeRange] = [
TimeRange(startTime: 6, endTime: 9),
TimeRange(startTime: 9, endTime: 12),
TimeRange(startTime: 12, endTime: 15),
TimeRange(startTime: 15, endTime: 18),
TimeRange(startTime: 18, endTime: 21),
TimeRange(startTime: 21, endTime: 24),
TimeRange(startTime: 24, endTime: 30)
]
func overlaps(_ availability: TimeRange) -> Bool {
return (startTime ..< endTime).overlaps(availability.startTime ..< availability.endTime)
}
}
extension TimeRange {
private func string(forHour hour: Int) -> String {
switch hour % 24 {
case 0: return NSLocalizedString("Midnight", comment: "Hour text")
case 1...11: return "\(hour % 12)" + NSLocalizedString("am", comment: "Hour text")
case 12: return NSLocalizedString("Noon", comment: "Hour text")
default: return "\(hour % 12)" + NSLocalizedString("pm", comment: "Hour text")
}
}
var text: String {
return string(forHour: Int(startTime)) + "-" + string(forHour: Int(endTime))
}
}
struct Availability {
let dayOfWeek: DayOfWeek
let timeRange: TimeRange
init(dayOfWeek: DayOfWeek, timeRange: TimeRange) {
self.dayOfWeek = dayOfWeek
self.timeRange = timeRange
}
init?(dictionary: [String: Any]) {
guard
let dayOfWeekRaw = dictionary["dayOfWeek"] as? DayOfWeek.RawValue,
let dayOfWeek = DayOfWeek(rawValue: dayOfWeekRaw),
let startTime = dictionary["startTime"] as? Double,
let endTime = dictionary["endTime"] as? Double
else {
return nil
}
self.dayOfWeek = dayOfWeek
self.timeRange = TimeRange(startTime: startTime, endTime: endTime)
}
var dictionary: [String: Any] {
return [
"dayOfWeek": dayOfWeek.rawValue,
"startTime": timeRange.startTime,
"endTime": timeRange.endTime
]
}
}
extension Availability {
func overlaps(_ availability: Availability) -> Bool {
return dayOfWeek == availability.dayOfWeek && timeRange.overlaps(availability.timeRange)
}
}
我正在构建一个应用程序,提供类似于遛狗的服务。遛狗的人可以上传可以遛狗的日期和时间。我没有让他们选择像 1 月 1 日星期一这样的实际日期,而是让他们选择一周中的任何几天以及他们有空的任何时间。
我遇到的问题是我不知道如何为它构建数据模型。
照片中的是一个带有单元格的 collectionView,在每个单元格中我都显示了他们可以选择的可用日期和时间段。一周中的每一天都有相同的 7 个时间段,想要成为遛狗者的用户可以从中选择。
问题是,如果有人选择 Sun 6am-9am、12pm-3pm 和 6pm-9pm,但他们也选择 Mon 6am-9m,我如何构建可以区分日期和时间的数据模型。例如星期天早上 6 点到 9 点和星期一早上 6 点到 9 点,如何区分?这些时间段应该是双打还是字符串?
这是我目前用于 collectionView 数据源和单元格的内容:
// the collectionView's data source
var tableData = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
//cellForItem
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: availabilityCell, for: indexPath) as! AvailabilityCell
cell.clearCellForReuse()
cell.dayOfWeek = tableData[indexPath.item]
// inside the AvailabilityCell itself
var dayOfWeek: String? {
didSet {
dayOfWeekLabel.text = dayOfWeek
}
}
func clearCellForReuse() {
dayOfWeekLabel.text = nil
// deselect whatever radio buttons were selected to prevent scrolling issues
}
进一步解释一下最终会发生什么,当想要遛狗的用户滚动查看谁有空时,如果他们滚动的日期和时间不在该人的任何日期和时间上谁 posted(周日和周一,选择的时间)不可用,那么他们的 post 不应该出现在提要中,但如果是那些日子之一和那些时间之一,那么他们的post 将出现在提要中(在示例中,如果某人在周日晚上 10 点滚动,则不应出现此 post)。数据模型中的任何内容都将与 post 当前滚动的任何日期和时间进行比较。我在后端使用 Firebase。
我想出的东西相当复杂,这就是为什么我需要更合理的东西。
class Availability {
var monday: String?
var tuesday: String?
var wednesday: String?
var thursday: String?
var friday: String?
var saturday: String?
var sunday: String?
var slotOne: Double? // sunday 6am-9am I was thinking about putting military hours here that's why I used a double
var slotTwo: Double? // sunday 9am-12pm
var slotTwo: Double? // sunday 12pm-3pm
// these slots would continue all through saturday and this doesn't seem like the correct way to do this. There would be 49 slots in total (7 days of the week * 7 different slots per day)
}
我也考虑过将它们分成不同的数据模型,例如星期一 class、星期二 class 等,但这似乎也行不通,因为它们都必须是相同的数据collectionView 数据源的类型。
更新 在@rob 的回答中,他给了我一些见解,让我可以对我的代码进行一些更改。我还在消化它,但我仍然有几个问题。他做了一个cool project that shows his idea.
1- 由于我将数据保存到 Firebase 数据库,数据应该如何结构化才能保存?可以有多个时间相似的日子。
2- 我仍然在思考 rob 的代码,因为我以前从未处理过时间范围,所以这对我来说很陌生。我仍然不知道要根据什么进行排序,尤其是回调内部的时间范围
// someone is looking for a dog walker on Sunday at 10pm so the initial user who posted their post shouldn't appear in the feed
let postsRef = Database().database.reference().child("posts")
postsRef.observe( .value, with: { (snapshot) in
guard let availabilityDict = snapshot.value as? [String: Any] else { return }
let availability = Availability(dictionary: availabilityDict)
let currentDayOfWeek = dayOfTheWeek()
// using rob;s code this compares the days and it 100% works
if currentDayOfWeek != availability.dayOfWeek.text {
// don't add this post to the array
return
}
let currentTime = Calendar.current.dateComponents([.hour,.minute,.second], from: Date())
// how to compare the time slots to the current time?
if currentTime != availability.??? {
// don't add this post to the array
return
}
// if it makes this far then the day and the time slots match up to append it to the array to get scrolled
})
func dayOfTheWeek() -> String? {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "EEEE"
return dateFormatter.stringFromDate(self)
}
猫皮有很多方法,但我可能会将可用性定义为日期枚举和时间范围:
struct Availability {
let dayOfWeek: DayOfWeek
let timeRange: TimeRange
}
你的星期几可能是:
enum DayOfWeek: String, CaseIterable {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
或者你也可以这样做:
enum DayOfWeek: Int, CaseIterable {
case sunday = 0, monday, tuesday, wednesday, thursday, friday, saturday
}
它们是 Int
和 String
的优缺点。在基于 Web 的 Firestore UI 中,字符串表示形式更易于阅读。整数表示提供了更容易的排序潜力。
您的时间范围:
typealias Time = Double
typealias TimeRange = Range<Time>
extension TimeRange {
static let allCases: [TimeRange] = [
6 ..< 9,
9 ..< 12,
12 ..< 15,
15 ..< 18,
18 ..< 21,
21 ..< 24,
24 ..< 30
]
}
在与 Firebase 交互方面,它不理解枚举和范围,所以我定义了一个 init
方法和 dictionary
属性 来映射到 [String: Any]
可以与 Firebase 交换的词典:
struct Availability {
let dayOfWeek: DayOfWeek
let timeRange: TimeRange
init(dayOfWeek: DayOfWeek, timeRange: TimeRange) {
self.dayOfWeek = dayOfWeek
self.timeRange = timeRange
}
init?(dictionary: [String: Any]) {
guard
let dayOfWeekRaw = dictionary["dayOfWeek"] as? DayOfWeek.RawValue,
let dayOfWeek = DayOfWeek(rawValue: dayOfWeekRaw),
let startTime = dictionary["startTime"] as? Double,
let endTime = dictionary["endTime"] as? Double
else {
return nil
}
self.dayOfWeek = dayOfWeek
self.timeRange = startTime ..< endTime
}
var dictionary: [String: Any] {
return [
"dayOfWeek": dayOfWeek.rawValue,
"startTime": timeRange.lowerBound,
"endTime": timeRange.upperBound
]
}
}
您还可以定义一些扩展以使其更易于使用,例如,
extension Availability {
func overlaps(_ availability: Availability) -> Bool {
return dayOfWeek == availability.dayOfWeek && timeRange.overlaps(availability.timeRange)
}
}
extension TimeRange {
private func string(forHour hour: Int) -> String {
switch hour % 24 {
case 0: return NSLocalizedString("Midnight", comment: "Hour text")
case 1...11: return "\(hour % 12)" + NSLocalizedString("am", comment: "Hour text")
case 12: return NSLocalizedString("Noon", comment: "Hour text")
default: return "\(hour % 12)" + NSLocalizedString("pm", comment: "Hour text")
}
}
var text: String {
return string(forHour: Int(lowerBound)) + "-" + string(forHour: Int(upperBound))
}
}
extension DayOfWeek {
var text: String {
switch self {
case .sunday: return NSLocalizedString("Sunday", comment: "DayOfWeek text")
case .monday: return NSLocalizedString("Monday", comment: "DayOfWeek text")
case .tuesday: return NSLocalizedString("Tuesday", comment: "DayOfWeek text")
case .wednesday: return NSLocalizedString("Wednesday", comment: "DayOfWeek text")
case .thursday: return NSLocalizedString("Thursday", comment: "DayOfWeek text")
case .friday: return NSLocalizedString("Friday", comment: "DayOfWeek text")
case .saturday: return NSLocalizedString("Saturday", comment: "DayOfWeek text")
}
}
}
如果你不想使用Range
,你可以将TimeRange
定义为struct
:
enum DayOfWeek: String, CaseIterable {
case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}
extension DayOfWeek {
var text: String {
switch self {
case .sunday: return NSLocalizedString("Sunday", comment: "DayOfWeek text")
case .monday: return NSLocalizedString("Monday", comment: "DayOfWeek text")
case .tuesday: return NSLocalizedString("Tuesday", comment: "DayOfWeek text")
case .wednesday: return NSLocalizedString("Wednesday", comment: "DayOfWeek text")
case .thursday: return NSLocalizedString("Thursday", comment: "DayOfWeek text")
case .friday: return NSLocalizedString("Friday", comment: "DayOfWeek text")
case .saturday: return NSLocalizedString("Saturday", comment: "DayOfWeek text")
}
}
}
struct TimeRange {
typealias Time = Double
let startTime: Time
let endTime: Time
}
extension TimeRange {
static let allCases: [TimeRange] = [
TimeRange(startTime: 6, endTime: 9),
TimeRange(startTime: 9, endTime: 12),
TimeRange(startTime: 12, endTime: 15),
TimeRange(startTime: 15, endTime: 18),
TimeRange(startTime: 18, endTime: 21),
TimeRange(startTime: 21, endTime: 24),
TimeRange(startTime: 24, endTime: 30)
]
func overlaps(_ availability: TimeRange) -> Bool {
return (startTime ..< endTime).overlaps(availability.startTime ..< availability.endTime)
}
}
extension TimeRange {
private func string(forHour hour: Int) -> String {
switch hour % 24 {
case 0: return NSLocalizedString("Midnight", comment: "Hour text")
case 1...11: return "\(hour % 12)" + NSLocalizedString("am", comment: "Hour text")
case 12: return NSLocalizedString("Noon", comment: "Hour text")
default: return "\(hour % 12)" + NSLocalizedString("pm", comment: "Hour text")
}
}
var text: String {
return string(forHour: Int(startTime)) + "-" + string(forHour: Int(endTime))
}
}
struct Availability {
let dayOfWeek: DayOfWeek
let timeRange: TimeRange
init(dayOfWeek: DayOfWeek, timeRange: TimeRange) {
self.dayOfWeek = dayOfWeek
self.timeRange = timeRange
}
init?(dictionary: [String: Any]) {
guard
let dayOfWeekRaw = dictionary["dayOfWeek"] as? DayOfWeek.RawValue,
let dayOfWeek = DayOfWeek(rawValue: dayOfWeekRaw),
let startTime = dictionary["startTime"] as? Double,
let endTime = dictionary["endTime"] as? Double
else {
return nil
}
self.dayOfWeek = dayOfWeek
self.timeRange = TimeRange(startTime: startTime, endTime: endTime)
}
var dictionary: [String: Any] {
return [
"dayOfWeek": dayOfWeek.rawValue,
"startTime": timeRange.startTime,
"endTime": timeRange.endTime
]
}
}
extension Availability {
func overlaps(_ availability: Availability) -> Bool {
return dayOfWeek == availability.dayOfWeek && timeRange.overlaps(availability.timeRange)
}
}