我有一个对象数组,其中每个对象都有一个练习名称和一个随机数量的代表。
然后我有一个生成随机锻炼的功能(其中有3到6个练习)
然而,当我打印它时,代表几乎总是1,2或偶尔14,尽管加载它30次左右。
我在这里做错了吗?
这是我的对象和结构:
struct exerciseInWorkout {
let name : String
let reps : Int
}
let exerciseBankArray = [
exerciseInWorkout(name: "Squat", reps: (Int(arc4random_uniform(10)))),
exerciseInWorkout(name: "Push Ups", reps: (Int(arc4random_uniform(5)))),
exerciseInWorkout(name: "Viking Press", reps: (Int(arc4random_uniform(20)))),
]
这是我的功能:
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: exerciseBankArray[randomKey].reps)}
print (workoutSet)
}
}
另外,有没有办法创建一组这些以避免两次相同的练习?我尝试使用Set,但似乎根本没用。
最后,当我打印它时,每个对象前面加上“project.exerciseInWorkout ...有没有办法只打印/返回干净的数组,即[[”name:“press ups”,reps:12], [姓名:xyz,代表:30]]?
原因是我想将它传递给一个新的VC,然后放入一个表视图,并假设我需要一个干净的数组来做到这一点。
答案 0 :(得分:3)
您的数组exerciseBankArray
似乎全局存储,这意味着exerciseInWorkout
组件会为整个应用初始化一次。话虽如此,然后正常的是,rep的数量总是相同的,arc4random_uniform
仅在第一次访问时执行。
如果你想保持相同的结构,我推荐这个
从arc4random_uniform
移除exerciseBankArray
,然后写下您想要的最大代表数量
let exerciseBankArray = [
exerciseInWorkout(name: "Squat", maxReps: 10),
exerciseInWorkout(name: "Push Ups", maxReps: 5),
exerciseInWorkout(name: "Viking Press", maxReps: 20)
]
像{/ p>一样调用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))
)
}
}
当你说删除全局变量时,你的意思是在每个需要它们的VC中存储练习数组吗?我只是认为那会“重复自己”(从DRY原则等?)
我完全同意DRY指南,但有很多方法可以不重复。全局变量(一个不在任何类中,只是自由浮动的变量)的问题很多:
另外,如果我改为上面的第二个例子,那我怎么称呼呢? 适量的那些?只需将“return exerciseInWorkout”替换为 新功能?或者它会保持不变,因为功能是 包含在结构中?
所以我理解正确,你真正想要创建的是一组默认生成器,用于具有名称和最大重复次数的练习,这些应该在整个项目中可用(因此你使用全局变量的原因)
改进此代码的一个好方法是定义静态生成器,例如,您可以将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中创建对象)。
希望有所帮助!