Короткий ответ
Похоже, ваш массив exerciseBankArray
хранится глобально, что означает, что exerciseInWorkout
компоненты инициализируются один раз для всего приложения. Сказав это, тогда нормально, что количество повторений всегда одинаково, arc4random_uniform
выполняется только при первом доступе.
Быстрое исправление
Если вы хотите сохранить ту же структуру, я рекомендую это
удалите arc4random_uniform
из exerciseBankArray
и просто напишите максимальное количество повторений, которое вы хотите
let exerciseBankArray = [
exerciseInWorkout(name: "Squat", maxReps: 10),
exerciseInWorkout(name: "Push Ups", maxReps: 5),
exerciseInWorkout(name: "Viking Press", maxReps: 20)
]
Вызвать случайную функцию внутри generateWorkout()
вот так
func generateWorkout(){
let possibleExercises = exerciseBankArray
let numberOfExercisesKey = Int(arc4random_uniform(4) + 3)
let workoutSet : [exerciseInWorkout] = (1...numberOfExercisesKey).map { _ in
let randomKey = Int(arc4random_uniform(UInt32(possibleExercises.count)))
return exerciseInWorkout(
name: exerciseBankArray[randomKey].name,
reps: Int(arc4random_uniform(exerciseBankArray[randomKey].maxReps))
)
}
}
Дольше улучшений
Если вы готовы создать лучшую архитектуру для своего кода, вот несколько советов
- Удалить глобальные переменные
Разделите вашу модель для упражнений на два класса / структуры:
Тот, который представляет собой фактическое упражнение
struct WorkoutExercise {
let name: String
let reps: Int
}
Тот, который представляет генератор упражнений
struct WorkoutExerciseGenerator {
let name: String
let maxReps: Int
// Add any other parameter you need to generate a good exercise
func generate() -> WorkoutExercise {
return WorkoutExercise(
name: name,
reps: Int(arc4random_uniform(maxReps))
)
}
}
Больше улучшений / Q & A
Когда вы говорите, что удаляете глобальные переменные, вы имеете в виду хранить массив упражнений в каждом VC, который нуждается в них? Я просто подумал, что это будет «повторение» (из принципов СУХОЙ и т. Д.)
Я полностью согласен с правилами СУХОГО, но есть много способов не повторяться. Проблема с глобальными переменными (переменная, которая не находится внутри какого-либо класса, просто свободно плавающая), многочисленна:
- Становится неловко, когда вы хотите включить его в разные цели
- Он не является частью какого-либо пространства имен, поэтому может перегружать другое из другой библиотеки файлов, портить автозаполнение и т. Д ...
- и т.д ... вы можете найти больше документации в этой теме
Кроме того, если я перейду ко 2-му примеру, приведенному выше, как мне тогда вызвать
правильное количество тех? Просто замените «returnercInWorkout» на
новая функция? Или это будет неизменным, потому что функция
содержится в структуре?
Так что я правильно понимаю, что вы действительно хотите создать набор генераторов по умолчанию для упражнений, которые имеют имя и максимальное количество повторений, и они должны быть доступны во всем проекте (следовательно, почему вы использовали глобальные переменные) .
Хороший способ улучшить этот код - определить статические генераторы, например, вы можете обновить WorkoutExerciseGenerator
до
struct WorkoutExerciseGenerator {
let name: String
let maxReps: Int
// Add any other parameter you need to generate a good exercise
func generate() -> WorkoutExercise {
return WorkoutExercise(
name: name,
reps: Int(arc4random_uniform(maxReps))
)
}
// Generates a "Squat" workout
static var squat {
return WorkoutExerciseGenerator(name: "Squat", maxReps: 10)
}
// Generates a "Push Up" workout
static var pushUp {
return WorkoutExerciseGenerator(name: "Push Ups", maxReps: 5)
}
// Generates a "Viking Press" workout
static var vikingPress {
return WorkoutExerciseGenerator(name: "Viking Press", maxReps: 20)
}
}
Теперь, когда у вас есть эти конкретные генераторы, похоже, вы также хотите иметь способ генерировать целую тренировку. Если это так, то вы можете просто создать, в дополнение к тому, о чем я писал, некоторые объекты для представления тренировки и генератора тренировки.
/// This represents a whole workout that contains
/// multiple exercises
struct Workout {
let exercises: [WorkoutExercise]
}
/// This allows to dynamically creates a Workout
struct WorkoutGenerator {
// This is the "pool" of exercises from
// which it generates a workout (similar to your
// `exerciseBankArray`)
let exercisePool: [ExerciseGenerators]
// Min and max amount of workouts
let minCount: Int
let maxCount: Int
// Generates a workout from the generator
func generate() -> WorkoutGenerator {
let amount = Int(arc4random_uniform(maxCount - minCount)) + minCount
let exercises = (0..<amount).map { _ in
// Selects an exercise generator at random
let index = Int(arc4random_uniform(exercisePool.count))
// Generates a random workout exercise from this generator
return exercisePool[index].generate()
}
return Workout(exercises: exercises)
}
// Same thing here, you can use a static variable to create
// a "default" workout generator that contains the exercises
// you had inside your `exerciseBankArray`
static var default: WorkoutGenerator {
return WorkoutGenerator(
exercisePool: [.squat, .pushUp, .vikingPress],
minCount: 3,
maxCount: 6
)
}
}
Теперь, когда у вас есть все это, единственное, что вам нужно сделать, чтобы создать абсолютно произвольную тренировку в соответствии с вашими требованиями, это
let myWorkout = WorkoutGenerator.default.generate()
Если вы хотите добавить больше типов упражнений, просто создайте больше статических ExerciseGenerator
, а если вы хотите создавать разные типы тренировок (возможно, с разными пулами упражнений, некоторые сложные или некоторые простые), просто создайте дополнительную статическую WorkoutGenerator
. (Обратите внимание, что вам не нужна статика, вы также можете просто создать объект прямо в вашем VC).
Надеюсь, это поможет!