Вы можете создать собственную сортировку, чтобы отсортировать даты по входящему дню рождения и передать свою коллекцию, отсортированную в метод ForEach:
extension Collection where Element == Birthday {
func sortedByIncomingBirthday() -> [Element] {
sorted {
// lhs date is today or is in the future
($0.date.month, $0.date.day) >= (Date().month, Date().day) ?
// rhs date is today or is in the future
($1.date.month, $1.date.day) >= (Date().month, Date().day) ?
// sort them by a month day order
($0.date.month, $0.date.day) < ($1.date.month, $1.date.day) :
// otherwise is in increasing order
true :
// lhs date is in the past
// sort them by a month day order
($0.date.month, $0.date.day) < ($1.date.month, $1.date.day)
}
}
}
ForEach(birthdays.sortedByIncomingBirthday(), id: \.self) { birthday in
Другой вариант - продлить день рождения и добавить свойство nextBirthday таким образом, вы можете отсортировать его, используя его в качестве keyPath для вашего NSSortDescriptor:
extension Date {
var isInToday: Bool { Calendar.current.isDateInToday(self) }
var nextBirthday: Date {
isInToday ? self : Calendar.current.nextDate(after: Date(), matching: Calendar.current.dateComponents([.month, .day, .hour, .minute], from: self), matchingPolicy: .nextTime)!
}
}
extension Birthday {
var nextBirthday: Date { date.nextBirthday }
}
NSSortDescriptor(keyPath: \Birthday.nextBirthday, ascending: true)
edit / update:
если свойство «Дата рождения» является необязательным, не принудительно разворачивайте его значение:
extension Birthday {
var nextBirthday: Date { date?.nextBirthday ?? .distantFuture }
}
, и первый подход также должен будет справиться с этим:
extension Collection where Element == Birthday {
func sortedByIncomingBirthday() -> [Element] {
sorted { lhs, rhs in
if lhs.date == nil { return false }
let lhs = lhs.date ?? .distantFuture
let rhs = rhs.date ?? .distantFuture
// lhs date is today or is in the future
return (lhs.month, lhs.day) >= (Date().month, Date().day) ?
// rhs date is today or is in the future
(rhs.month, rhs.day) >= (Date().month, Date().day) ?
// sort them by a month day order
(lhs.month, lhs.day) < (rhs.month, rhs.day) :
// otherwise is in increasing order
true :
// lhs date is in the past
// sort them by a month day order
(lhs.month, lhs.day) < (rhs.month, rhs.day)
}
}
}