Reputation: 5722
I can't figure out why I am getting the error on the second iteration in the loop. Can you help me understand where the problem comes from?
let NumTracks = 3
let TrackBytes = 2
func readBytes(input: [UInt8]?) {
if let input = input {
var input = input[0..<input.count]
for _ in 0..<NumTracks {
print(input[0..<TrackBytes]) // fatal error: Negative ArraySlice index is out of range
input = input[TrackBytes..<input.count]
}
}
}
let samples = [UInt8]?([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
readBytes(samples)
There is another test case like this one and no reason why this is crashing as well.
EDIT
I don't get the error when I use this code variation (and I still don't know why):
let NumTracks = 3
let TrackBytes = 2
func readBytes(input: [UInt8]?) {
if let input = input {
var input = input[0..<input.count]
for _ in 0..<NumTracks {
print(input[input.startIndex..<input.startIndex.advancedBy(2)])
input = input[input.startIndex.advancedBy(2)..<input.endIndex]
}
}
}
let samples = [UInt8]?([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
readBytes(samples)
Upvotes: 4
Views: 2531
Reputation: 539965
The reason is that taking an array slice preserves the original array indices:
let array = [1, 2, 3, 4]
let slice = array[1 ..< 3]
print(slice) // [2, 3]
print(slice.startIndex) // 1
print(slice.endIndex) // 3
print(slice[1]) // 2 (the first element of the slice)
print(slice[0]) // fatal error: Index out of bounds
In your case, after the first call to
input = input[TrackBytes..<input.count]
the first valid index for input
is TrackBytes
and not 0
and
therefore the next call to
input[0..<TrackBytes]
causes the runtime error.
So the startIndex
of a collection is not necessarily zero and you already found a solution, another one is
func readBytes(input: [UInt8]?) {
if let input = input {
var input = input[0..<input.count]
for _ in 0..<NumTracks {
print([UInt8](input.prefix(TrackBytes)))
input = input.suffixFrom(input.startIndex + TrackBytes)
}
}
}
or even shorter, without modifying a local array slice repeatedly:
func readBytes(input: [UInt8]?) {
if let input = input {
for start in 0.stride(to: NumTracks * TrackBytes, by: TrackBytes) {
print([UInt8](input[start ..< start + TrackBytes]))
}
}
}
Upvotes: 8