Неправильная ссылка на случайное число в объекте Swift - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть массив объектов, каждый из которых имеет имя упражнения и случайное количество повторений.

Затем у меня есть функция для генерации произвольной тренировки (с 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], [name: xyz, reps: 30]]?

Причина в том, что я хочу передать это новому VC, чтобы затем поместить в табличное представление и предположить, что для этого мне нужен чистый массив.

1 Ответ

0 голосов
/ 25 апреля 2018

Короткий ответ

Похоже, ваш массив exerciseBankArray хранится глобально, что означает, что exerciseInWorkout компоненты инициализируются один раз для всего приложения. Сказав это, тогда нормально, что количество повторений всегда одинаково, arc4random_uniform выполняется только при первом доступе.


Быстрое исправление

Если вы хотите сохранить ту же структуру, я рекомендую это

  1. удалите arc4random_uniform из exerciseBankArray и просто напишите максимальное количество повторений, которое вы хотите

    let exerciseBankArray = [
    
        exerciseInWorkout(name: "Squat", maxReps: 10),
        exerciseInWorkout(name: "Push Ups", maxReps: 5),
        exerciseInWorkout(name: "Viking Press", maxReps:  20)
    
    ]
    
  2. Вызвать случайную функцию внутри 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))
             )
        } 
    }
    

Дольше улучшений

Если вы готовы создать лучшую архитектуру для своего кода, вот несколько советов

  1. Удалить глобальные переменные
  2. Разделите вашу модель для упражнений на два класса / структуры:

    • Тот, который представляет собой фактическое упражнение

      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, который нуждается в них? Я просто подумал, что это будет «повторение» (из принципов СУХОЙ и т. Д.)

Я полностью согласен с правилами СУХОГО, но есть много способов не повторяться. Проблема с глобальными переменными (переменная, которая не находится внутри какого-либо класса, просто свободно плавающая), многочисленна:

  1. Становится неловко, когда вы хотите включить его в разные цели
  2. Он не является частью какого-либо пространства имен, поэтому может перегружать другое из другой библиотеки файлов, портить автозаполнение и т. Д ...
  3. и т.д ... вы можете найти больше документации в этой теме

Кроме того, если я перейду ко 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).

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...