swiftswitch-statementfatal-errorexc-bad-instruction

Fatal error: Range end index has no valid successor


So i have a problem using the Switch statement, when i used it with a range i get this "Fatal error: Range end index has no valid successor" in the console.

var ArrayBytes : [UInt8] = [48 ,48 ,48]
 var SuperArrayMensaje : Array = [[UInt8]]()
var num7BM : Array = [UInt8]()

    for var Cont27 = 0; Cont27 < 800; Cont27++ {

        ArrayBytesReservaSrt = String(Mensaje7BM[Cont27])

        switch Mensaje7BM[Cont27] {

        case 0...9 :
                     num7BM = Array(ArrayBytesReservaSrt.utf8)
                     ArrayBytes.insert(num7BM[0], atIndex: 2)

        case 10...99 :
                     num7BM = Array(ArrayBytesReservaSrt.utf8)
                     ArrayBytes.insert(num7BM[0], atIndex: 1)
                     ArrayBytes.insert(num7BM[1], atIndex: 2)

        case 100...255 : // --> THE problem is here "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
                     num7BM = Array(ArrayBytesReservaSrt.utf8) 
                     ArrayBytes.insert(num7BM[0], atIndex: 0)
                     ArrayBytes.insert(num7BM[1], atIndex: 1)
                     ArrayBytes.insert(num7BM[2], atIndex: 2)


        default : break

        }

    SuperArrayMensaje.insert(ArrayBytes, atIndex: Cont27)

                ArrayBytes = [48 ,48 ,48]
    }

Solution

  • The problem can be reproduced with this MCVE:

    let u = 255 as UInt8
    
    switch u {
    case 0...9: print("one")
    case 10...99: print("two")
    case 100...255: print("three")
    }
    

    And to a degree, we see the problem if we simply try to create a range variable that would cover this range:

    let r = Range<UInt8>(start: 100, end: 256)
    

    This doesn't compile. First, we must note that the end argument for the Range constructor is not included in the range.

    The range 100...255 is equivalent to 100..<256. If we try to construct that range, we get the compile error:

    Integer literal '256' overflows when stored into 'UInt8'

    We can't create a range which includes the max value for that integer type. Problematically, there's no UInt8 value larger than 255. That's needed because for something to be contained within a range, it must be smaller than the end value of the range. That is, it must return true when compared with the < operator. And there's no UInt8 value that can make this statement: 255 < n return true. Therefore, 255 can never be in a range of type UInt8.

    So, we have to find a different approach.

    As the programmer, we can know that the range we're trying to create representing all the three digit decimal numbers that fit in UInt8, we could just use the default case here:

    let u = 255 as UInt8
    
    switch u {
    case 0...9: print("one")
    case 10...99: print("two")
    default: print("three")
    }
    

    This seems the simplest solution. I like this option best because we don't end up with a default case that we know will never execute.

    If we really explicitly want a case that captures all of the values from 100 to UInt8 max, we can also do this:

    switch u {
    case 0...9: print("one")
    case 10...99: print("two")
    case 100..<255, 255: print("three")
    default: print("how did we end up here?")
    }
    

    Or like this:

    switch u {
    case 0...9: print("one")
    case 10...99: print("two")
    case 100...255 as ClosedInterval: print("three")
    default: print("default")
    }
    

    For more reading on the ClosedInterval, see the Apple documentation or Swift doc.