Search code examples
swiftexceptionswift3nsdata

Handling NSData (Data) range exceptions


Using NSData (or Data) for reading bytes using getBytes (copyBytes) can throw NSRangeException. I don't know how to catch them.

I know that for NS classes, including NSData, I would have to use Objective-C wrapper to catch and handle exception but I am a bit surprised to see that Data also throws exception that Swift cannot handle natively.

Am I missing something obvious? Is there a way I can catch those using pure Swift? Or is there any other method that throws Swift handleable errors?

Code example that fails (in reality I am using data created from file)

// Using NSData

let dataBytes:[UInt8] = [0xff, 0x00, 0x11, 0x22]
let data = NSData(bytes: dataBytes, length: dataBytes.count)
let dataRange = NSRange(location: 2, length: 4)

var result = [UInt8](repeating: 0, count: 4)

do
{
    try data.getBytes(&result, range: dataRange)
    print("OK")
}
catch
{
    print("FAIL")
}


// Using Data

let dataBytes:[UInt8] = [0xff, 0x00, 0x11, 0x22]
let data = Data(dataBytes)
let dataRange = Range(2..<6)

var result = [UInt8](repeating: 0, count: 4)

do
{
    try data.copyBytes(to: &result, from: dataRange)
    print("OK")
}
catch
{
    print("FAIL")
}

Note: Code in question also shows two warnings (as expected, because Swift is not capable of handling those) but I added those try...catch block just to show what I want to use.

No calls to throwing functions occur within 'try' expression

'catch' block is unreachable because no errors are thrown in 'do' block


Solution

  • You need to check that the the upper index of the range you're using isn't out of range for your Data:

    if dataRange.upperBound <= data.count {
        data.copyBytes(to: &result, from: dataRange)
    }
    

    You can think of Data more like an array/collection. copyBytes will fail without a catchable exception for the same reason anArray[1] will fail for a single item array.