Extracting sub elements from Data struct

I am trying to use the subdata method of the structure Data.

So far I have been unsuccessful in creating a range of type Range<Data.index>


let myArray:Array<UInt8> = [ 1, 2, 3, 4, 5 ]
print( myArray)
let chunk = Data(myArray)
let subChunk = chunk.subdata( in: 1...2 )

Perhaps someone could explain how Range<Data.index> is different and or where I might find some informative documentation.

I get the following error.

No '...' candidates produce the expected contextual result type 'Range<Data.Index>' (aka 'Range<Int>')

Accepted Reply

is this Swift 3 ?


if so, take care of difference between open and closed range.


Did you try : chunk.subdata(in : 1..<3)

Replies

is this Swift 3 ?


if so, take care of difference between open and closed range.


Did you try : chunk.subdata(in : 1..<3)

Claude, many thanks for your answer. It works for the playground answer. So many thenks.


The playground example is the simplified form of:


            let subRange = sendDataIndex!..<(sendDataIndex! + amountToSend)
            let chunk = dataToSend?.subdata(in: subRange)
            //let chunk = dataToSend?.subdata(in: sendDataIndex!..<(sendDataIndex! + amountToSend))


What I don't understand is why I get an error for line 02. but not for 03. (when 03. is un-commented and 01. & 02. are commented out.)


The error is : Cannot convert value of type 'CountableRange<Int>' to expected argument type 'Range<Data.Index>' (aka 'Range<Int>')

The '..<' operator can signify a Range or a CountableRange when the bounds are integers, so the compiler defaults to CountableRange when a range expression with integer bounds is in a statement that provides no context to suggest the expression should be regarded as Range.



let chunk = dataToSend?.subdata(in: sendDataIndex!..<(sendDataIndex! + amountToSend))


The 'subdata(in:)' method requires a Range argument, so the range expression with integer bounds provided as its argument will be inferred from the context to be Range and the statement will compile.



let subRange = sendDataIndex!..<(sendDataIndex! + amountToSend)


In contrast, without the context of the method call or any other hint in that statement, the range expression with integer bounds is ambiguous, so the compiler will default to regarding it as CountableRange, and then the following line will not compile because the 'in:' parameter is Range but subRange is CountableRange.


let chunk = dataToSend?.subdata(in: subRange)



If you had written:


let subRange: Range = sendDataIndex! ..< (sendDataIndex! + amountToSend)


then the explicit type annotation, Range, would have told the compiler to regard the range expression as Range instead of CountableRange, and then the line that didn't compile would have compiled.



Also, you can create a Range from a CountableRange with:


Range(someCountableRange)




Finally, consider using optional binding ('if let ...' and 'guard let ...') instead of force unwrapping a variable unless you are absolutely sure that the variable will never contain nil or you specifically do want a nil value to crash the program.

Goldsdad, thanks for going the extra mile on this excellent explanation.

Greatly appreciated, Ven.