Ios Swift:通过HTTP发送大型数字数组([Double])的最佳方式
我想在几个小时的无结论性研究和测试之后,我会问: 介绍 我正试图将非常大的Ios Swift:通过HTTP发送大型数字数组([Double])的最佳方式,ios,json,swift,http,Ios,Json,Swift,Http,我想在几个小时的无结论性研究和测试之后,我会问: 介绍 我正试图将非常大的Doubles数组从应用程序发送到服务器,当然,我希望尽可能地压缩它。 具体而言,这些数组包含CMDeviceMotion组件(加速度、x、y、z、陀螺仪等),但此问题应适用于任何大的数字数组(超过100K或一百万个值) 通过研究选项,我尝试并发现了什么 假设我有一个大数组Double(还有许多其他数组): var CMX=CM.map({$0.userAcceleration.x}) 这里,CMX属于[Double]
Double
s数组从应用程序发送到服务器,当然,我希望尽可能地压缩它。
具体而言,这些数组包含CMDeviceMotion
组件(加速度、x、y、z、陀螺仪等),但此问题应适用于任何大的数字数组(超过100K或一百万个值)
通过研究选项,我尝试并发现了什么
假设我有一个大数组Double
(还有许多其他数组):
var CMX=CM.map({$0.userAcceleration.x})
这里,CMX
属于[Double]
类型,CM
属于[CMDeviceMotion]
我尝试通过以不同方式发送CMX
向我的服务器发出POST
请求,然后在服务器上收到请求后计算总大小:
{“AX”:"-0.0441827848553658,-0.103976868093014,-0.117475733160973,-0.206566318869591,-0.266509801149368,-0.282151937484741,-0.260240525007248,-0.266505032777786,-0.315020948648453,-0.305839896202087,0.0255246963351965,0.0783950537443161,0.0749507397413254,0.0760494321584702,-0.0101579604670405,0.106710642576218,0.131824940443039,0.0630970001220703,0.21177926659584,0.27022996544838,0.222621202468872,0.234281644225121,0.288497060537338,0.176655143499374,0.193904414772987,0.169417425990105,0.150193274021149,0.00871349219232798,-0.0270088445395231,-0.0 ....
NSKeyedArchiver
将数组转换为Data
对象,并在发送数据之前对数据进行base 64编码:
[“AX”:NSKeyedArchiver.archivedData(withRootObject:CM.map({$0.userAcceleration.x})).base64EncodedString()]
这使得文件大小为206KB
[“AX”:CM.map({$0.userAcceleration.x})]
事实证明,这个数字数组实际上被转换成了一个逗号分隔的字符串,大小与试用版1中的相同(160Kb)
[“AX”:NSKeyedArchiver.archivedData(withRootObject:CM.map({$0.userAcceleration.x}))
使应用程序在运行时崩溃,因此我无法将数据
对象作为JSON中的值发送
问题:
如何在JSON对象中以更精简的方式发送这些数组
请注意,我已经考虑过降采样,并使用32位浮点来减小大小。简单的方法是:
let data: Data = CMX.withUnsafeBufferPointer { pointer in
return Data(buffer: pointer)
}
你有一个二进制缓冲区,所有的双精度浮点数加在一起
但由于HTTP是基于文本的协议,因此您必须将此数据
转换为base64字符串:
let base64String = data.base64EncodedString()
这个base64String
应该为POST
(?)HTTP
请求的AX
参数传递
编辑:
要将其转换回,可以使用以下代码:
extension Array {
init?(data: Data) {
// This check should be more complex, but here we just check if total byte count divides to one element size in bytes
guard data.count % MemoryLayout<Element>.size == 0 else { return nil }
let elementCount = data.count / MemoryLayout<Element>.size
let buffer = UnsafeMutableBufferPointer<Element>.allocate(capacity: elementCount)
data.copyBytes(to: buffer)
self = buffer.map({$0})
buffer.deallocate()
}
// Wrapped here code above
var data: Data {
return self.withUnsafeBufferPointer { pointer in
return Data(buffer: pointer)
}
}
}
let converted: [Double]? = Array(data: CMX.data) // converted now should be equal to CMX
扩展数组{
初始化?(数据:数据){
//这个检查应该更复杂,但这里我们只检查总字节数是否除以一个以字节为单位的元素大小
guard data.count%MemoryLayout.size==0 else{return nil}
让elementCount=data.count/MemoryLayout.size
let buffer=UnsafeMutableBufferPointer.allocate(容量:elementCount)
data.copyBytes(到:缓冲区)
self=buffer.map({$0})
buffer.deallocate()
}
//在这里包装上面的代码
var数据:数据{
返回self.withUnsafeBufferPointer{pointer in
返回数据(缓冲区:指针)
}
}
}
let converted:[Double]?=Array(data:CMX.data)//现在转换的值应该等于CMX
您可以尝试压缩数据字符串,并将其发送base64编码,或者尝试获取Double的二进制表示形式(如此处:)并发送base64 Encode64。任何压缩方法都会要求了解数据的潜在模式。例如,数据范围、顺序是否重要、固定十进制数等。您可能会看到,甚至有一个非常棒的答案!这将文件大小降低到82 Kb(从153)对于64位double和40 Kb的32位FloatsHi,再次感谢您的帮助。如何将数据转换回数组?@kmn,已添加到答案中