Универсальная функция со структурами

#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()