Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
往返Swift编号类型到/从数据_Swift_Swift3_Swift Data - Fatal编程技术网

往返Swift编号类型到/从数据

往返Swift编号类型到/从数据,swift,swift3,swift-data,Swift,Swift3,Swift Data,Swift 3倾向于数据而不是[UInt8],因此我试图找出将各种数字类型(UInt8、Double、Float、Int64等)作为数据对象进行编码/解码的最有效/惯用方法 有,但它似乎使用了各种指针API,我在数据上找不到 我想介绍一些定制扩展,它们看起来像: let input = 42.13 // implicit Double let bytes = input.data let roundtrip = bytes.to(Double) // --> 42.13 我已经浏览了很多

Swift 3倾向于
数据
而不是
[UInt8]
,因此我试图找出将各种数字类型(UInt8、Double、Float、Int64等)作为数据对象进行编码/解码的最有效/惯用方法

有,但它似乎使用了各种指针API,我在数据上找不到

我想介绍一些定制扩展,它们看起来像:

let input = 42.13 // implicit Double
let bytes = input.data
let roundtrip = bytes.to(Double) // --> 42.13

我已经浏览了很多文档,但真正让我困惑的是如何从任何基本结构(所有数字都是)中获得某种指针(OpaquePointer、BufferPointer或UnsafePointer?)。在C语言中,我只需在它前面打一个符号,就可以了。

您可以使用以下命令获得指向可变对象的不安全指针:

我不知道如何为不可变对象获取一个,因为inout操作符只适用于可变对象


这在您链接到的答案中得到了证明。

您可以使用以下方法获得指向可变对象的不安全指针:

我不知道如何为不可变对象获取一个,因为inout操作符只适用于可变对象

这在您链接到的答案中得到了演示。

注意:现在已为Swift 5(Xcode 10.2)更新了代码。(可以在编辑历史记录中找到Swift 3和Swift 4.2版本。)现在还可以正确处理未对齐的数据

如何从值创建
数据
从Swift 4.2开始,只需使用

let value = 42.13
let data = withUnsafeBytes(of: value) { Data($0) }

print(data as NSData) // <713d0ad7 a3104540>
这种方法有一个问题:它要求内存与类型的属性对齐(此处:与8字节地址对齐)。但这并不能保证,例如,如果数据是作为另一个
数据
值的切片获得的

因此,将字节复制到值更安全:

let data = Data([0x71, 0x3d, 0x0a, 0xd7, 0xa3, 0x10, 0x45, 0x40])
var value = 0.0
let bytesCopied = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
assert(bytesCopied == MemoryLayout.size(ofValue: value))
print(value) // 42.13
说明:

  • 使用覆盖值的原始字节的可变缓冲区指针调用闭包
  • DataProtocol
    (数据符合该方法)将字节从数据复制到该缓冲区
copyBytes()
的返回值是复制的字节数。它等于目标缓冲区的大小,如果数据没有包含足够的字节,则等于或小于目标缓冲区的大小

通用解决方案#1 上述转换现在可以很容易地实现为
结构数据的通用方法

extension Data {

    init<T>(from value: T) {
        self = Swift.withUnsafeBytes(of: value) { Data($0) }
    }

    func to<T>(type: T.Type) -> T? where T: ExpressibleByIntegerLiteral {
        var value: T = 0
        guard count >= MemoryLayout.size(ofValue: value) else { return nil }
        _ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: $0)} )
        return value
    }
}
类似地,您可以将数组转换为
数据
并返回:

extension Data {

    init<T>(fromArray values: [T]) {
        self = values.withUnsafeBytes { Data($0) }
    }

    func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
        var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
        _ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
        return array
    }
}
protocol DataConvertible {
    init?(data: Data)
    var data: Data { get }
}
extension Int : DataConvertible { }
extension Float : DataConvertible { }
extension Double : DataConvertible { }
// add more types here ...
  • 将转换作为协议扩展中的默认方法实现:

    extension DataConvertible where Self: ExpressibleByIntegerLiteral{
    
        init?(data: Data) {
            var value: Self = 0
            guard data.count == MemoryLayout.size(ofValue: value) else { return nil }
            _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
            self = value
        }
    
        var data: Data {
            return withUnsafeBytes(of: self) { Data($0) }
        }
    }
    
    我在这里选择了一个失败的初始值设定项,它检查提供的字节数 匹配类型的大小

  • 最后声明所有类型的一致性,这些类型可以安全地转换为
    数据
    并返回:

    extension Data {
    
        init<T>(fromArray values: [T]) {
            self = values.withUnsafeBytes { Data($0) }
        }
    
        func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
            var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
            _ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
            return array
        }
    }
    
    protocol DataConvertible {
        init?(data: Data)
        var data: Data { get }
    }
    
    extension Int : DataConvertible { }
    extension Float : DataConvertible { }
    extension Double : DataConvertible { }
    // add more types here ...
    
  • 这使得转换更加优雅:

    let value = 42.13
    let data = value.data
    print(data as NSData) // <713d0ad7 a3104540>
    
    if let roundtrip = Double(data: data) {
        print(roundtrip) // 42.13
    }
    
    或者在您自己的类型中实现转换方法来执行任何需要的操作 因此需要序列化和反序列化一个值

    字节顺序 上述方法不进行字节顺序转换,数据始终为 主机字节顺序。对于独立于平台的表示(例如。 “big-endian”又名“network”字节顺序),使用相应的整数 财产。初始化者。例如:

    let value = 1000
    let data = value.bigEndian.data
    print(data as NSData) // <00000000 000003e8>
    
    if let roundtrip = Int(data: data) {
        print(Int(bigEndian: roundtrip)) // 1000
    }
    
    let值=1000
    让数据=value.bigEndian.data
    打印(数据作为NSData)//
    如果让往返=Int(数据:数据){
    打印(Int(bigEndian:roundtrip))//1000
    }
    
    当然,这种转换通常也可以在泛型中完成 转换方法。

    注:Swift 5(Xcode 10.2)的代码现已更新。(可以在编辑历史记录中找到Swift 3和Swift 4.2版本。)现在还可以正确处理未对齐的数据

    如何从值创建
    数据
    从Swift 4.2开始,只需使用

    let value = 42.13
    let data = withUnsafeBytes(of: value) { Data($0) }
    
    print(data as NSData) // <713d0ad7 a3104540>
    
    这种方法有一个问题:它要求内存与类型的属性对齐(此处:与8字节地址对齐)。但这并不能保证,例如,如果数据是作为另一个
    数据
    值的切片获得的

    因此,将字节复制到值更安全:

    let data = Data([0x71, 0x3d, 0x0a, 0xd7, 0xa3, 0x10, 0x45, 0x40])
    var value = 0.0
    let bytesCopied = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
    assert(bytesCopied == MemoryLayout.size(ofValue: value))
    print(value) // 42.13
    
    说明:

    • 使用覆盖值的原始字节的可变缓冲区指针调用闭包
    • DataProtocol
      (数据符合该方法)将字节从数据复制到该缓冲区
    copyBytes()
    的返回值是复制的字节数。它等于目标缓冲区的大小,如果数据没有包含足够的字节,则等于或小于目标缓冲区的大小

    通用解决方案#1 上述转换现在可以很容易地实现为
    结构数据的通用方法

    extension Data {
    
        init<T>(from value: T) {
            self = Swift.withUnsafeBytes(of: value) { Data($0) }
        }
    
        func to<T>(type: T.Type) -> T? where T: ExpressibleByIntegerLiteral {
            var value: T = 0
            guard count >= MemoryLayout.size(ofValue: value) else { return nil }
            _ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: $0)} )
            return value
        }
    }
    
    类似地,您可以将数组转换为
    数据
    并返回:

    extension Data {
    
        init<T>(fromArray values: [T]) {
            self = values.withUnsafeBytes { Data($0) }
        }
    
        func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
            var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
            _ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
            return array
        }
    }
    
    protocol DataConvertible {
        init?(data: Data)
        var data: Data { get }
    }
    
    extension Int : DataConvertible { }
    extension Float : DataConvertible { }
    extension Double : DataConvertible { }
    // add more types here ...
    
  • 将转换作为协议扩展中的默认方法实现:

    extension DataConvertible where Self: ExpressibleByIntegerLiteral{
    
        init?(data: Data) {
            var value: Self = 0
            guard data.count == MemoryLayout.size(ofValue: value) else { return nil }
            _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
            self = value
        }
    
        var data: Data {
            return withUnsafeBytes(of: self) { Data($0) }
        }
    }
    
    我在这里选择了一个失败的初始值设定项,它检查提供的字节数 匹配类型的大小

  • 最后声明所有类型的一致性,这些类型可以安全地转换为
    数据
    并返回:

    extension Data {
    
        init<T>(fromArray values: [T]) {
            self = values.withUnsafeBytes { Data($0) }
        }
    
        func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
            var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
            _ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
            return array
        }
    }
    
    protocol DataConvertible {
        init?(data: Data)
        var data: Data { get }
    }
    
    extension Int : DataConvertible { }
    extension Float : DataConvertible { }
    extension Double : DataConvertible { }
    // add more types here ...
    
  • 这使得转换更加优雅:

    let value = 42.13
    let data = value.data
    print(data as NSData) // <713d0ad7 a3104540>
    
    if let roundtrip = Double(data: data) {
        print(roundtrip) // 42.13
    }
    
    或者在您自己的类型中实现转换方法来执行任何需要的操作 因此需要序列化和反序列化一个值

    字节顺序 上述方法不进行字节顺序转换,数据始终为 主机字节顺序。对于独立于平台的表示(例如。 “big-endian”又名“network”字节顺序),使用相应的整数 财产。初始化者。例如:

    let value = 1000
    let data = value.bigEndian.data
    print(data as NSData) // <00000000 000003e8>
    
    if let roundtrip = Int(data: data) {
        print(Int(bigEndian: roundtrip)) // 1000
    }
    
    let值=1000
    让数据=value.bigEndian.data
    打印(数据作为NSData)//
    如果让往返=Int(数据:数据){
    打印(Int(bigEndian:roundtrip))//1000
    }
    
    当然,这种转换通常也可以在泛型中完成 对流