Swift 3.2自定义洗牌函数无法打乱OfferCard数组问题
Hey there, let's figure out why your shuffle function isn't behaving as expected! It's frustrating when you’ve tweaked code multiple times and one feature still won’t cooperate—let’s break this down step by step.
You mentioned that sometimes the first element of your array stays the same after shuffling (like "Apple Music" remaining at the top), even though removeFirst() works fine. Let’s start by looking at your custom shuffle implementation and potential issues in Swift 3.2.
Possible Fixes & Improvements
1. Simplify the Shuffle Extension for Int Indexes
Your current shuffle uses the correct Fisher-Yates algorithm, but the generic MutableCollection implementation with IndexDistance type conversions might introduce subtle edge cases. Since you’re working with Array (which uses Int indexes), simplify the extension to avoid ambiguity:
extension MutableCollection where Index == Int { mutating func shuffle() { guard count > 1 else { return } // Fisher-Yates shuffle: iterate from the end to the start for i in stride(from: count - 1, through: 1, by: -1) { // Generate a random index between 0 and i (inclusive) let randomIndex = Int(arc4random_uniform(UInt32(i + 1))) swapAt(i, randomIndex) } } } // Add a non-mutating version to return a fresh shuffled array extension Collection { func shuffled() -> [Element] { var shuffledArray = Array(self) shuffledArray.shuffle() return shuffledArray } }
2. Use the Non-Mutating shuffled() Method
Instead of mutating an existing array, use the new shuffled() method to get a clean, shuffled copy. This makes your displayOfferCards() code cleaner and avoids confusion around value-type semantics:
func displayOfferCards() -> Void { let offerCards = allOfferCards().shuffled() // Get a new shuffled array for (index, offerCard) in offerCards.enumerated() { let delay = Double(index) * 0.2 offerCard.display(delay: delay) } }
3. Verify Shuffle Behavior with Full Array Logs
Sometimes the first element staying the same is just random chance! To confirm if the shuffle is actually working, print the entire array before and after shuffling:
func displayOfferCards() -> Void { let originalCards = allOfferCards() print("Before shuffle: \(originalCards.map { $0.yourCardTitleProperty })") // Replace with your actual card identifier let shuffledCards = originalCards.shuffled() print("After shuffle: \(shuffledCards.map { $0.yourCardTitleProperty })") for (index, offerCard) in shuffledCards.enumerated() { let delay = Double(index) * 0.2 offerCard.display(delay: delay) } }
If only the first element stays the same occasionally but others are rearranged, that’s normal randomness. If the entire array is unchanged every time, double-check that allOfferCards() isn’t returning a static array (your working removeFirst() makes this unlikely, though).
4. Check for Edge Cases
If your array has only 1 or 2 elements, the shuffle won’t change much by design. Ensure numberOfCards from your data source returns a value greater than 1 during testing.
Why Your Original Extension Might Have Issues
Your generic extension is technically correct, but in Swift 3.2, the IndexDistance type conversions (from Int to UInt32 and back) could lead to unexpected behavior in rare cases—especially if you were working with non-Int indexed collections. The simplified version removes that ambiguity while keeping the valid Fisher-Yates logic.
内容的提问来源于stack exchange,提问作者Steven Matthews

