保存结构的最快方法iOS/Swift [英] Fastest way to save structs iOS / Swift

查看:50
本文介绍了保存结构的最快方法iOS/Swift的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有类似的结构

struct RGBA: Codable {
        
   var r: UInt8
   var g: UInt8
   var b: UInt8
   var a: UInt8 
}

我要保存大量的这种结构(> 1_000_000)

I want save large amount of this structs (>1_000_000)

解码

guard let history = try? JSONDecoder().decode(HistoryRGBA.self, from: data) else { return }

编码

guard let jsonData = try? encoder.encode(dataForSave) else { return false }

如何改善编码/解码时间和RAM内存量?

How can I improve encoding/decoding time and amount of RAM memory?

推荐答案

考虑到所有属性均为 UInt8 (字节),您可以使结构符合 ContiguousBytes 并保存其原始字节:

Considering that all your properties are UInt8 (bytes) you can make your struct conform to ContiguousBytes and save its raw bytes:

struct RGBA {
   let r, g, b, a: UInt8
}


extension RGBA: ContiguousBytes {
    func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
        try Swift.withUnsafeBytes(of: self) { try body($0) }
    }
}


extension ContiguousBytes {
    init<T: ContiguousBytes>(_ bytes: T) {
        self = bytes.withUnsafeBytes { $0.load(as: Self.self) }
    }
}


extension RGBA: ExpressibleByArrayLiteral {
    typealias ArrayLiteralElement = UInt8
    init(arrayLiteral elements: UInt8...) {
        self.init(elements)
    }
}


extension Array {
    var bytes: [UInt8] { withUnsafeBytes { .init($0) } }
    var data: Data { withUnsafeBytes { .init($0) } }
}


extension ContiguousBytes {
    var bytes: [UInt8] { withUnsafeBytes { .init($0) } }
    var data: Data { withUnsafeBytes { .init($0) } }
}


extension ContiguousBytes {
    func object<T>() -> T { withUnsafeBytes { $0.load(as: T.self) } }
    func objects<T>() -> [T] { withUnsafeBytes { .init($0.bindMemory(to: T.self)) } }
}


extension ContiguousBytes {
    var rgba: RGBA { object() }
    var rgbaCollection: [RGBA] { objects() }
}


extension UIColor {
    convenience init<T: Collection>(_ bytes: T) where T.Index == Int, T.Element == UInt8 {
        self.init(red:   CGFloat(bytes[0])/255,
                  green: CGFloat(bytes[1])/255,
                  blue:  CGFloat(bytes[2])/255,
                  alpha: CGFloat(bytes[3])/255)
    }
}


extension RGBA {
    var color: UIColor { .init(bytes) }
}


let red: RGBA = [255, 0, 0, 255]
let green: RGBA = [0, 255, 0, 255]
let blue: RGBA = [0, 0, 255, 255]

let redBytes = red.bytes            // [255, 0, 0, 255]
let redData = red.data              // 4 bytes
let rgbaFromBytes = redBytes.rgba    // RGBA
let rgbaFromData = redData.rgba      // RGBA
let colorFromRGBA = red.color       // r 1.0 g 0.0 b 0.0 a 1.0
let rgba: RGBA = [255,255,0,255]    // RGBA yellow
let yellow = rgba.color             // r 1.0 g 1.0 b 0.0 a 1.0

let colors = [red, green, blue]      // [{r 255, g 0, b 0, a 255}, {r 0, g 255, b 0, a 255}, {r 0, g 0, b 255, a 255}]
let colorsData = colors.data          // 12 bytes
let colorsFromData = colorsData.rgbaCollection // [{r 255, g 0, b 0, a 255}, {r 0, g 255, b 0, a 255}, {r 0, g 0, b 255, a 255}]

编辑/更新:

struct LayerRGBA {
    var canvas: [[RGBA]]
}


extension LayerRGBA {
    var data: Data { canvas.data }
    init(_ data: Data) { canvas = data.objects() }
}


struct AnimationRGBA {
    var layers: [LayerRGBA]
}


extension AnimationRGBA {
    var data: Data { layers.data }
    init(_ data: Data) {
        layers = data.objects()
    }
}


struct HistoryRGBA {
    var layers: [LayerRGBA] = []
    var animations: [AnimationRGBA] = []
}


extension HistoryRGBA {
    var data: Data {
        let layersData = layers.data
        return layersData.count.data + layersData + animations.data
    }
    init(data: Data)  {
        let index = Int(Data(data.prefix(8))).advanced(by: 8)
        self.init(layers: data.subdata(in: 8..<index).objects(),
                  animations: data.subdata(in: index..<data.endIndex).objects())
    }
}


extension Numeric {
    var data: Data {
        var bytes = self
        return .init(bytes: &bytes, count: MemoryLayout<Self>.size)
    }
}


extension Numeric {
    init<D: DataProtocol>(_ data: D) {
        var value: Self = .zero
        let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
        self = value
    }
}


游乐场测试:


Playground testing:

let layer1: LayerRGBA = .init(canvas: [colors,[red],[green, blue]])
let layer2: LayerRGBA = .init(canvas: [[red],[green, rgba]])
let loaded: LayerRGBA = .init(layer1.data)
loaded.canvas[0]
loaded.canvas[1]
loaded.canvas[2]

let animationRGBA: AnimationRGBA = .init(layers: [layer1,layer2])
let loadedAnimation: AnimationRGBA = .init(animationRGBA.data)
loadedAnimation.layers.count // 2
loadedAnimation.layers[0].canvas[0]
loadedAnimation.layers[0].canvas[1]
loadedAnimation.layers[0].canvas[2]
loadedAnimation.layers[1].canvas[0]
loadedAnimation.layers[1].canvas[1]

let hRGBA: HistoryRGBA = .init(layers: [loaded], animations: [animationRGBA])
let loadedHistory: HistoryRGBA = .init(data: hRGBA.data)
loadedHistory.layers[0].canvas[0]
loadedHistory.layers[0].canvas[1]
loadedHistory.layers[0].canvas[2]

loadedHistory.animations[0].layers[0].canvas[0]
loadedHistory.animations[0].layers[0].canvas[1]
loadedHistory.animations[0].layers[0].canvas[2]
loadedHistory.animations[0].layers[1].canvas[0]
loadedHistory.animations[0].layers[1].canvas[1]

这篇关于保存结构的最快方法iOS/Swift的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆