如何在Swift中获取任意数组的字节大小?

时间:2020-12-30 21:43:32

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 rawDataFromArray = NSData(bytes:myArray,length:???),但不知道如何获取数组的字节长度。以下是我的数组可以是什么的一些示例:

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?

如何获取数组的字节大小?谁能告诉我正确的方法呢?或者也许只是在Swift中将Array转换为NSData并不是一个好习惯?

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.

我还看到将Swift数组转换为NSData用于持久存储并将字节数组转换为NSData和自定义数组转换为NSData,但无法弄清楚如何为这种任意数组获取字节大小。

1 个解决方案

#1


5  

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

似乎存在一种误解:对于每种类型T,T的所有实例具有相同的大小,可以计算为sizeof(T)。在数组的情况下,数组元素之间可以有填充,因此arr1所需的总大小是

arr1.count * strideof(Int)

(Compare e.g. Swift: How to use sizeof? for the subtle differences between sizeof() and strideof()).

(比较例如Swift:如何使用sizeof?来解决sizeof()和strideof()之间的细微差别。

Therefore a generic function to create NSData from an array would be

因此,从数组创建NSData的通用函数将是

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.

使用withUnsafeBufferPointer()可确保阵列为其元素使用连续存储。

In the case of "simple" types like Int and Float this gives the expected results:

在“简单”类型的情况下,如Int和Float,这给出了预期的结果:

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.

因为struct String包含指向实际字符存储的(隐藏/未记录的)指针。

One possibility would be to append each string as a NUL-terminated UTF-8 string:

一种可能性是将每个字符串附加为NUL终止的UTF-8字符串:

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.

或者,在您引用的线程中使用NSKeyedArchiver。

#1


5  

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

似乎存在一种误解:对于每种类型T,T的所有实例具有相同的大小,可以计算为sizeof(T)。在数组的情况下,数组元素之间可以有填充,因此arr1所需的总大小是

arr1.count * strideof(Int)

(Compare e.g. Swift: How to use sizeof? for the subtle differences between sizeof() and strideof()).

(比较例如Swift:如何使用sizeof?来解决sizeof()和strideof()之间的细微差别。

Therefore a generic function to create NSData from an array would be

因此,从数组创建NSData的通用函数将是

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.

使用withUnsafeBufferPointer()可确保阵列为其元素使用连续存储。

In the case of "simple" types like Int and Float this gives the expected results:

在“简单”类型的情况下,如Int和Float,这给出了预期的结果:

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.

因为struct String包含指向实际字符存储的(隐藏/未记录的)指针。

One possibility would be to append each string as a NUL-terminated UTF-8 string:

一种可能性是将每个字符串附加为NUL终止的UTF-8字符串:

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.

或者,在您引用的线程中使用NSKeyedArchiver。