This is a practical question, i'm sending a file by breaking it into trunks of, say, 1000 bytes
data = NSData.dataWithContentsOfFile(path)
var dataPackage : [Byte](count: 1000, repeatedValue: 0)
for offset = 0; offset < data.length; {
// omit some range check here
data.getBytes(&dataPackage, NSRange(location: offset, length: 1000))
send(dataPackage)
}
Everything was great, until I want to insert a sequence number into dataPackage, at position 0, so naturally, I would change the above to
data.getBytes(&dataPackage[1], NSRange(location: offset, length: 999))
It turned out that only 1 single element is copied to dataPackage. The rest 999 elements were copied to dont-know-where
My question is, 1) how to make this work, and 2) how array in swift is addressed, in such a way that &data[i] = &data + i (as shown in the 1st example) but &data[i+k] != &data[i] + k
Edit: I solved (1) by doing
data.getBytes(&dataPackage + 1, NSRange(location: offset, length: 999))
Question (2) remains
Do not getBytes(&dataPackage[i] + k, ..)
, I think, this may causes "access violation"
Consider this code:
struct MyStruct {
var _val = [Int](count: 1000, repeatedValue: 0);
subscript(idx:Int) -> Int {
get {
println("get: [\(idx)] -> val(\(_val[idx]))")
return _val[idx]
}
set(val) {
println("set: [\(idx)] old(\(_val[idx])) -> new(\(val))")
_val[idx] = val
}
}
}
func myFunc(ptr:UnsafeMutablePointer<Int>, val:Int) {
println("mutating: ptr(\(ptr)) <- \(val)")
ptr.memory = val
}
MyStruct
is just a wrapper around Array
.
myFunc
receives a mutable pointer and mutates the value of it.
With this, when yo do:
var foo = MyStruct()
myFunc(&foo[1], 12)
outputs:
get: [1] -> val(0)
mutating: ptr(0x00007fff561619d8) <- 12
set: [1] old(0) -> new(12)
See?
- Copy the value to
somewhere
- Mutate the value of
somewhere
- Write-back from
somewhere
I don't know where somewhere
is, though.
When you do like:
var foo = MyStruct()
myFunc(&foo[1] + 1, 12)
outputs:
get: [1] -> val(0)
set: [1] old(0) -> new(0)
mutating: ptr(0x00007fff5c0b79e0) <- 12
This time, my guess would be:
- Copy the value to
somewhere
- let
corrupted
as somewhere + 1
- Write-back with unmutated value from
somewhere
- Discard
somewhere
- Mutate the value of
corrupted
On the other hand, when you do:
var foo = [Int](count:1000, repeatedValue:0)
myFunc(&foo + 1, 12)
This means:
- let
ptr
as the pointer of the first element of foo
- let
ptr
as ptr + 1
- Mutate the value of
ptr
As a result, foo[1]
will be 12
successfully as you did.
Actually in-out(&
) of Array
is very special as mentioned in the document.
When a function is declared as taking an UnsafeMutablePointer argument, it can accept any of the following:
- nil, which is passed as a null pointer
- An UnsafeMutablePointer value
- An in-out expression whose operand is a stored lvalue of type Type, which is passed as the address of the lvalue
- An in-out [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call
Only the built-in Array
has the last feature.
So, when you pass ¬AnArrayLvalue
(including &array[i]
) to UnsafeMutablePointer<Type>
parameter, the length should be always 1
, and you should not +
or -
it.