簡體   English   中英

無法正確引用Swift對象中的隨機數

[英]Not correctly referencing random number in Swift object

我有一個對象數組,其中每個對象都有一個“練習名稱”和隨機次數的代表。

然后,我有一個功能可以生成隨機鍛煉(其中包含3至6個鍛煉)

但是,當我打印它時,盡管加載了30次左右,但代表幾乎總是1、2或偶爾是14。

我在這里做錯什么了嗎?

這是我的對象和結構:

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 ...”,有什么方法可以只打印/返回干凈的數組,即[[“名稱:” press ups“,reps:12],[name: xyz,代表:30]]?

原因是我想將其傳遞給新的VC,然后放在表格視圖中,並假定我需要一個干凈的陣列來做到這一點。

簡短答案

看來您的數組exerciseBankArray是全局存儲的,這意味着對整個應用程序初始化一次exerciseInWorkout組件。 話雖如此,然后代表的次數總是相同是正常的,所以arc4random_uniform僅在第一次訪問時執行。


快速解決

如果要保持相同的結構,我建議您這樣做

  1. exerciseBankArray刪除arc4random_uniform ,然后寫下所需的最大次數

     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)) ) } } 

更多改進/問答

當您說刪除全局變量時,是指將練習數組存儲在需要它們的每個VC中嗎? 我只是認為那將是“重復自己”(根據DRY原則等?)

我完全同意DRY准則,但是有很多方法可以避免重復。 全局變量(一個不在任何類內的變量,只是自由浮動)的問題很多:

  1. 當您想要將其包含在不同目標中時,它會變得尷尬
  2. 它不是任何名稱空間的一部分,因此它可能會使另一個文件庫中的另一個過載,並弄亂了自動完成功能,等等。
  3. 等等...您可以在此線程中找到更多文檔

另外,如果我更改為上面的第二個示例,那么該如何稱呼這些數量呢? 只需用新功能替換“ return ExerciseInWorkout”? 還是因為func包含在結構中而不會改變?

因此,我理解正確,您真正想要創建的是一組具有名稱和最大次數的練習的默認生成器,並且這些應在整個項目中可用(因此,為什么要使用全局變量)。

改進此代碼的一個好方法是定義靜態生成器,例如,您可以將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中創建對象)。

希望有幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM