3

Here is my code (largeAsteroids.count is never 0):

var largeAsteroids=[[SKTexture]]()
func randomLargeAsteroidTextures()->Array<SKTexture>{
        let i=Int(arc4random())%largeAsteroids.count
        return largeAsteroids[i]// this line triggers EXC_BREAKPOINT
    }

When I execute my code, I receive no errors but I get a EXC_BREAKPOINT. I ensured there wasn't any breakpoint and at index i there was a valid object. enter image description here

First I changed SKTexture to AnyObject, it didn't help. Then I tried to use NSMutableArray instead of swift array, problem still exist:

var largeAsteroids=NSMutableArray()
    func randomLargeAsteroidTextures()->AnyObject{
        let i=Int(arc4random())%largeAsteroids.count
        return largeAsteroids.objectAtIndex(i) // this line triggers EXC_BREAKPOINT
    }

update:

Problem solved, replace:

let i=Int(arc4random())%largeAsteroids.count

by:

let i=Int(arc4random_uniform(UInt32(largeAsteroids.count)))

Thanks for Matt's solution:

You should probably be using arc4random_uniform. You'll get modulo bias from your current implementation. – Matt Gibson

Yongxu Ren
  • 111
  • 6
  • 1
    What does `println("i is \(i), count is \(largeAsteroids.count)")` print? – Jesper Aug 06 '14 at 07:35
  • func randomLargeAsteroidTextures()->Array{ print("??") let i=Int(arc4random())%largeAsteroids.count println("i is \(i), count is \(largeAsteroids.count)") return largeAsteroids[i] } printed result: ??i is 3, count is 7 ??i is 5, count is 7 ??(lldb) when it crashes, the second print does not execute but EXC_BREAKPOINT pointed to return largeAsteroids[i] – Yongxu Ren Aug 06 '14 at 09:28
  • You should probably be using `arc4random_uniform`. You'll get modulo bias from your current implementation. – Matt Gibson Aug 06 '14 at 09:28
  • Thank you Matt! I change to let i=Int(arc4random_uniform(UInt32(largeAsteroids.count))), it seems working fine. – Yongxu Ren Aug 06 '14 at 09:41
  • @YongxuRen I've added an answer to explain what was actually causing your problem (your array index was sometimes negative due to an unsigned-to-signed conversion on a 32-bit platform.) – Matt Gibson Aug 06 '14 at 11:15

1 Answers1

7

You were running on a 32-bit target, yes? On a 32-bit target (e.g. iPhone 4), Swift Ints are 32-bits, and signed. However, on any platform, arc4random() returns a 32-bit unsigned integer.

Because of this conflict, and your conversion to Int, Int(arc4random()), sometimes—in fact, half the time, all else being equal—your number was negative, giving you a negative array index, and causing your problem (though I get EXC_BAD_INSTRUCTION, as I'd expect, when I reproduce the problem; presumably you have a breakpoint set for exceptions?)

My suggestion, to use arc4random_uniform, should work fine as long as the count of your asteroids is never more than Int.max on a 32-bit platform, which is presumably quite unlikely, unless you're giving your gamer a really hard time. It will also avoid modulo bias in the random generation, so your resulting random numbers will be more uniformly distributed than in your original solution.

Matt Gibson
  • 37,886
  • 9
  • 99
  • 128
  • 1
    Yes This is exactly what the problem was. I cleaned all my breakpoints before execution, but I get EXC_BREAKPOINT everytime. I guess it is probably a bug in xcode 6(or swift). – Yongxu Ren Aug 06 '14 at 18:30
  • This happend to me as well. The next morning when I was looking through that code I was like... *facepalm*, "I'm dumb!" – Sethmr Dec 30 '16 at 15:19