#ios #swift
Вопрос:
Я пытаюсь создать многоразовую функцию. Он выбирает данные только за текущую неделю. Но мне нужно использовать эту функцию несколько раз в своем приложении, поэтому я решил сделать ее универсальной.
У меня есть две структуры
struct BodyWeightCalendarModel {
let weight: Float
let date: Date
}
struct RetrievedWorkoutsByExercise {
let exerciseTitle: String
let sets: Int
let maxWeight: Int
let maxReps: Int
let date: Date
let volume: Int
}
func loopForWeek<T> (data: [T], completionHandler: ([T]) -> Void) {
let arrayForPeriod2: [T] = []
for value in data where value.date >= (calendar.currentWeekBoundary()?.startOfWeek)! amp;amp; value.date <= (calendar.currentWeekBoundary()?.endOfWeek)! {
arrayForPeriod.append(value)
}
completionHandler(arrayForPeriod2)
}
Как получить доступ к значениям данных? Я не могу получить доступ через «value.data».
Поэтому я хочу использовать эту функцию для разных структур (но все эти структуры должны иметь поле «дата»).
Комментарии:
1. Универсальный тип T не имеет значения даты. Я изо всех сил пытаюсь понять ваше мышление, но если вы хотите его абстрагировать, я думаю, что решение, которое вы ищете, было бы лучше выполнить с помощью протокола с полем даты в нем.
Ответ №1:
Как упоминалось в других ответах, использование протокола со свойством даты имеет наибольший смысл в вашем случае. Однако теоретически вы также можете использовать ключевые пути для достижения этой цели. Вы можете создать функцию, которая берет любые экземпляры и получает из них даты аналогично тому, как показано ниже:
func printDates(data: [Any], keyPath:AnyKeyPath) {
for value in data {
if let date = value[keyPath: keyPath] as? Date {
print("date = (date)")
}
}
}
а затем передайте, например, свои экземпляры BodyWeightCalendarModel, как показано ниже:
let one = BodyWeightCalendarModel(date: Date(), weight: 1)
let two = BodyWeightCalendarModel(date: Date(), weight: 2)
printDates(data: [one, two], keyPath: BodyWeightCalendarModel.date)
Но все же протокол имеет больше смысла в вашем случае.
Ответ №2:
Причина, по которой вы не можете получить доступ value.date
, заключается в том, что ваша функция ничего не знает об T
этом . Ваша функция объявляет T
, но не ограничивает ее. Для компилятора T
может быть все, что угодно.
Вам нужно создать протокол, который сообщит вашей функции, чего ожидать, и приведет ваши структуры в соответствие с ним:
protocol Timed { // You might find a better name
var date: Date { get }
}
struct BodyWeightCalendarModel: Timed {
let date: Date
...
}
struct RetrievedWorkoutsByExercise: Timed {
let date: Date
...
}
Теперь вы можете ограничить T
Timed
, и ваша функция будет знать, что value
у date
нее есть свойство.
func loopForWeek<T: Timed> (data: [T], completionHandler: ([T]) -> Void) {
Ответ №3:
То, что ты пытаешься сделать, очень близко. Универсальное значение не обязательно имеет значение, называемое date
так, поэтому это не сработает. Вместо этого вы можете создать протокол, в котором указана переменная даты. С помощью этого протокола вы можете сделать что-то аккуратное с расширением.
protocol Dated {
var date: Date { get set }
}
extension Dated {
func loopForWeek() -> [Dated] {
let arrayForPeriod2: [Dated] = []
for value in date >= (calendar.currentWeekBoundary()?.startOfWeek)! amp;amp; value.date <= (calendar.currentWeekBoundary()?.endOfWeek)! {
arrayForPeriod.append(value)
}
return arrayForPeriod2
}
}
Затем мы можем заставить ваши две структуры использовать этот протокол следующим образом:
struct BodyWeightCalendarModel: Dated {
let date: Date
}
struct RetrievedWorkoutsByExercise: Dated {
let date: Date
}
И они могут вызывать функцию следующим образом:
let workouts = RetrievedWorkoutsByExercise()
let result = workouts.loopForWeek()