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

Posted

技术标签:

【中文标题】如何在 Swift 中获取任意数组的字节大小?【英文标题】:How to get bytes size for arbitrary array in Swift? 【发布时间】:2015-11-19 10:12:20 【问题描述】:

我想使用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

我不确定遍历数组的每个元素(如果字符串遍历每个字符,因为表情符号可能有更多字节表示它们)是否是正确的方法。

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

我也见过Converting Swift Array to NSData for persistent storage 和Converting array of bytes to NSData 和Custom Array to NSData,但不知道如何获取这种任意数组的字节大小。

【问题讨论】:

请参阅***.com/questions/25714086/… 以获取可用于整数或浮点数数组的示例。但是您不能简单地将 strings 数组视为 NSData,因为String 结构(具有固定大小)包含指向实际字符存储的不透明指针。 感谢@MartinR。因此,将字符串数组转换为 NSData 看起来是个坏主意。你能解释一下什么是不透明指针吗? struct String 具有不属于“可见”API 的成员(但您可以在调试器中看到它们)。其中一些是指向用于字符串的实际存储的指针。 (例如,相同的字符串可以共享​​>存储。) – 关键是struct String 不是自包含的。如果将其打包到 NSData 中,将其转移到其他地方并解包,它将包含无效指针。 – 当然,您可以从字符串数组创建 NSData,但必须单独附加每个字符串(例如,作为 NUL 终止的 UTF-8 字符串)。 或者,使用 NSKeyedArchiver (如在您引用的线程中)。这取决于您要如何处理数据。 【参考方案1】:

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

arr1.count * strideof(Int)

(比较例如Swift: How to use sizeof? 以了解sizeof()strideof() 之间的细微差别)。

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

extension Array 
    func asData() -> NSData 
        return self.withUnsafeBufferPointer(
            NSData(bytes: $0.baseAddress, length: count * strideof(Element))
        )
    

使用withUnsafeBufferPointer() 保证数组使用 其元素的连续存储。

对于像IntFloat 这样的“简单”类型,这给出了 预期结果:

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>

但是,对于字符串数组是没有用的:

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>

因为struct 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>

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

【讨论】:

strideof(T)MemoryLayout&lt;T&gt;.stride(截至... Swift 3?)

以上是关于如何在 Swift 中获取任意数组的字节大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中获取任意大小的空列表?

如何获取数组的大小? [复制]

swift 将任意长度的字节数组转换为Swift Int

java字节数组如何判断实际元素个数。

在 Swift 中打印数据的大小(兆字节)

将任意 Golang 接口转换为字节数组