Swift 3倾向于Data而不是[UInt8],我试图找出最有效/惯用的编码/解码方式,将各种数字类型(UInt8,Double,Float,Int64等)转换为Data对象。

有this answer for using [UInt8],但似乎使用各种指针API,我不能在数据上找到。

我想基本上一些自定义扩展看起来像:

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

这部分真的逃避了我,我看过一堆文档,是我怎么能从任何基本结构(所有的数字)得到一些指针事物(OpaquePointer或BufferPointer或UnsafePointer?)。在C,我只是在它前面拍了一个&符号,并有ya去。

如何从值创建数据

struct Data有一个初始化器

public init(bytes: UnsafeRawPointer,count: Int)

其可以以与对问题的各种答案类似的方式使用
How to convert a double into a byte array in swift?
您链接到:

let input = 42.13
var value = input
let data = withUnsafePointer(to: &value) {
    Data(bytes: UnsafePointer($0),count: MemoryLayout.size(ofValue: input))
}
print(data as NSData) // <713d0ad7 a3104540>

因为@zneak已经说过,你可以只取一个变量的地址,
因此,使用var value = value创建一个变量副本。
在早期的Swift版本中,你可以通过做
函数参数本身是一个变量,这不再支持了。

但是,使用初始化程序更容易

public init<SourceType>(buffer: UnsafeBufferPointer<SourceType>)

代替:

let input = 42.13
var value = input
let data = Data(buffer: UnsafeBufferPointer(start: &value,count: 1))
print(data as NSData) // <713d0ad7 a3104540>

请注意,通用占位符SourceType将从中自动推断
上下文。

如何从数据中检索值

NSData有一个bytes属性来访问底层存储。
struct数据有一个通用

public func withUnsafeBytes<ResultType,ContentType>(_ body: @noescape (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType

相反,它可以这样使用:

let data = Data(bytes: [0x71,0x3d,0x0a,0xd7,0xa3,0x10,0x45,0x40])
let value = data.withUnsafeBytes { (ptr: UnsafePointer<Double>) -> Double in
    return ptr.pointee
}
print(value) // 42.13

如果ContentType可以从上下文推断,则不需要指定它
在闭包中,这样可以简化为

let data = Data(bytes: [0x71,0x40])
let value: Double = data.withUnsafeBytes { $0.pointee }
print(value) // 42.13

通用解决方案#1

以上转换现在可以轻松实现为struct的通用方法Data:

extension Data {

    init<T>(from value: T) {
        var value = value
        self.init(buffer: UnsafeBufferPointer(start: &value,count: 1))
    }

    func to<T>(type: T.Type) -> T {
        return self.withUnsafeBytes { $0.pointee }
    }
}

例:

let input = 42.13 // implicit Double
let data = Data(from: input)
print(data as NSData) // <713d0ad7 a3104540>

let roundtrip = data.to(type: Double.self)
print(roundtrip) // 42.13

类似地,您可以将数组转换为数据并返回:

extension Data {

    init<T>(fromArray values: [T]) {
        var values = values
        self.init(buffer: UnsafeBufferPointer(start: &values,count: values.count))
    }

    func toArray<T>(type: T.Type) -> [T] {
        return self.withUnsafeBytes {
            [T](UnsafeBufferPointer(start: $0,count: self.count/MemoryLayout<T>.stride))
        }
    }
}

例:

let input: [Int16] = [1,Int16.max,Int16.min]
let data = Data(fromArray: input)
print(data as NSData) // <0100ff7f 0080>

let roundtrip = data.toArray(type: Int16.self)
print(roundtrip) // [1,32767,-32768]

通用解决方案#2

上述方法有一个缺点:
How to convert a double into a byte array in swift?,
它实际上只与“简单”
类型如整数和浮点类型。 “复杂”类型如Array
和String有(隐藏)指向底层存储的指针,不能
通过只复制结构本身传递。它也不会工作
引用类型只是指向真实对象存储的指针。

所以解决这个问题,一个可以

>定义一个协议,定义转换为数据并返回的方法:

protocol DataConvertible {
    init?(data: Data)
    var data: Data { get }
}

>在协议扩展中将转换实现为默认方法:

extension DataConvertible {

    init?(data: Data) {
        guard data.count == MemoryLayout<Self>.size else { return nil }
        self = data.withUnsafeBytes { $0.pointee }
    }

    var data: Data {
        var value = self
        return Data(buffer: UnsafeBufferPointer(start: &value,count: 1))
    }
}

我在这里选择一个可用的初始化程序,检查提供的字节数
匹配类型的大小。
>最后声明符合所有类型,可以安全地转换为数据并返回:

extension Int : DataConvertible { }
extension Float : DataConvertible { }
extension Double : DataConvertible { }
// add more types here ...

这使得转换更加优雅:

let input = 42.13
let data = input.data
print(data as NSData) // <713d0ad7 a3104540>

if let roundtrip = Double(data: data) {
    print(roundtrip) // 42.13
}

第二种方法的优点是,您不能无意中执行不安全的转化。
缺点是你必须显式列出所有“安全”类型。

您还可以为需要非平凡的其他类型实现协议
转换,如:

extension String: DataConvertible {
    init?(data: Data) {
        self.init(data: data,encoding: .utf8)
    }
    var data: Data {
        // Note: a conversion to UTF-8 cannot fail.
        return self.data(using: .utf8)!
    }
}

或者在你自己的类型中实现转换方法来做任何事情必须这样序列化和反序列化一个值。

往返Swift数字类型到/从数据的更多相关文章

  1. canvas中普通动效与粒子动效的实现代码示例

    canvas用于在网页上绘制图像、动画,可以将其理解为画布,在这个画布上构建想要的效果。本文详细的介绍了粒子特效,和普通动效进行对比,非常具有实用价值,需要的朋友可以参考下

  2. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. canvas学习和滤镜实现代码

    这篇文章主要介绍了canvas学习和滤镜实现代码,利用 canvas,前端人员可以很轻松地、进行图像处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  4. localStorage的过期时间设置的方法详解

    这篇文章主要介绍了localStorage的过期时间设置的方法详解的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. 详解HTML5 data-* 自定义属性

    这篇文章主要介绍了详解HTML5 data-* 自定义属性的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. HTML5的postMessage的使用手册

    HTML5提出了一个新的用来跨域传值的方法,即postMessage,这篇文章主要介绍了HTML5的postMessage的使用手册的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. 教你使用Canvas处理图片的方法

    本篇文章主要介绍了教你使用Canvas处理图片的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. ios – Swift语言:如何调用SecRandomCopyBytes

    从Objective-C,我可以这样做:在Swift中尝试这个时,我有以下内容:但我得到这个编译器错误:data.mutableBytes参数被拒绝,因为类型不匹配,但我无法弄清楚如何强制参数.解决方法这似乎有效:

  9. 使用Firebase iOS Swift将特定设备的通知推送到特定设备

    我非常感谢PushNotifications的帮助.我的应用聊天,用户可以直接向对方发送短信.但是如果没有PushNotifications,它就没有多大意义.它全部设置在Firebase上.如何将推送通知从特定设备发送到特定设备?

  10. ios – NSData to Data swift 3

    如何将此代码转换为使用Swift3数据?

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部