I'd like to use let rawDataFromArray = NSData(bytes: myArray, length: ???)
, but don't know how to get the bytes length for my array. Here are some examples of what could my array be:
let arr1 = [1, 2, 3]
let arr2 = [1.0, 23556789000.0]
let arr3 = ["hello", "ok", "π"]
func arrayLength(myArray: Array) -> Int {
var bytes = 0
for object in myArray {
// not sure what to do here
}
return bytes
}
I'm not sure if going through every element of the array (and in case of strings going through every character, since emojis could have more bytes representing them) is the proper way to do it.
How to get bytes size for array?
Could anyone tell me the proper way to do it?
Or maybe it's just that it is not good practice to convert Array
to NSData
in Swift?
I've also seen Converting Swift Array to NSData for persistent storage and Converting array of bytes to NSData and Custom Array to NSData, but couldn't figure out how to get bytes size for such arbitrary array.
To get the size of an array in Swift, use count function on the array. Following is a quick example to get the count of elements present in the array. array_name is the array variable name. count returns an integer value for the size of this array.
Swift doesn't have fixed size arrays, and I guess many of us have experimented with various workarounds.
This allows Swift to immediately allocate an array capable of holding 512 items, as opposed to creating a small array then re-allocating multiple times.
In Swift a byte is called a UInt8βan unsigned 8 bit integer. A byte array is a UInt8 array. In ASCII we can treat chars as UInt8 values. With the utf8 String property, we get a UTF8View collection. We can convert this to a byte array.
There seems to be a misunderstanding: For each type T
, all instances
of T
have the same size which can be computed as sizeof(T)
.
In the case of arrays, there can be a padding between array elements,
therefore the total size needed for arr1
is
arr1.count * strideof(Int)
(Compare e.g. Swift: How to use sizeof? for the subtle differences between sizeof()
and strideof()
).
Therefore a generic function to create NSData
from an array would be
extension Array {
func asData() -> NSData {
return self.withUnsafeBufferPointer({
NSData(bytes: $0.baseAddress, length: count * strideof(Element))
})
}
}
Using withUnsafeBufferPointer()
guarantees that the array uses
contiguous storage for its elements.
In the case of "simple" types like Int
and Float
this gives the
expected results:
let arr1 = [1, 2, 3]
print(arr1.asData())
// <01000000 00000000 02000000 00000000 03000000 00000000>
let arr2 = [1.0, 23556789000.0]
print(arr2.asData())
// <00000000 0000f03f 0000204c 60f01542>
However, it is useless for an array of strings:
let arr3 = ["hello", "ok", "π"]
print(arr3.asData())
// <945b2900 01000000 05000000 00000000 00000000 00000000 9a5b2900 01000000 02000000 00000000 00000000 00000000 068d2900 01000000 02000000 00000080 00000000 00000000>
because struct String
contains (hidden/undocumented) pointers to the actual
character storage.
One possibility would be to append each string as a NUL-terminated UTF-8 string:
let data3 = NSMutableData()
arr3.forEach { string in
string.withCString {
data3.appendBytes($0, length: Int(strlen($0)) + 1)
}
}
print(data3)
// <68656c6c 6f006f6b 00f09f91 8d00>
Alternatively, use NSKeyedArchiver
as in the threads that you referenced.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With