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

时间:2015-11-19 10:12:21

标签: ios arrays swift cocoa cocoa-touch

我想使用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 storageConverting array of bytes to NSData以及Custom Array to NSData,但无法弄清楚如何为这种任意数组获取字节大小。

1 个答案:

答案 0 :(得分:5)

似乎存在误解:对于每种类型T,所有实例 T的大小相同,可以计算为sizeof(T)。 对于数组,数组元素之间可以有填充, 因此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