首页 > 解决方案 > 在for循环中为元组赋值

问题描述

在 struct MIDIPacket 中有一个 UInt8 的元组。正常分配是这样的:

import CoreMIDI
let packet = MIDIPacket()
packet.data.0 = 0x02
packet.data.1 = 0x5f

等等。

这个元组的长度约为 128+。有一个转换后的值数组,我想将其分配给从某个索引开始的数据包。

let converted = [0x01, 0x02, 0x5e,...]
var k = packet starting index of assignment
for i in 0..<converted.count {
    packet.data(k) = converted[i]
    k += 1
}

我该怎么做呢?下标不起作用:例如packet.data[i],虽然我相信 Mirror 只是创建了数据包的副本,所以分配给它是行不通的。

let bytes = Mirror(reflecting: packet.data).children;
        for (_, b) in bytes.enumerated() {
                       
                   }

标签: swift

解决方案


没有用于执行此操作的官方 API,但 IIRC,同质元素类型的元组保证具有连续的内存布局。UnsafeBufferPointer您可以通过使用来读取/写入元组来利用这一点。

通常这需要您手动对元组的元素计数进行硬编码,但我编写了一些可以为您执行此操作的辅助函数。有两种变体,一个可变的,它可以让您获得一个UnsafeBufferPointer,您可以阅读(例如创建一个Array),一个可变的,它为您提供一个UnsafeMutableBufferPointer,您可以通过它分配元素。

enum Tuple {
    static func withUnsafeBufferPointer<Tuple, TupleElement, Result>(
        to value: Tuple,
        element: TupleElement.Type,
        _ body: (UnsafeBufferPointer<TupleElement>) throws -> Result
    ) rethrows -> Result {
        try withUnsafePointer(to: value) { tuplePtr in
            let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size
            
            return try tuplePtr.withMemoryRebound(
                to: TupleElement.self,
                capacity: count
            ) { elementPtr in
                try body(UnsafeBufferPointer(start: elementPtr, count: count))
            }
            
        }
    }
    
    static func withUnsafeMutableBufferPointer<Tuple, TupleElement, Result>(
        to value: inout Tuple,
        element: TupleElement.Type,
        _ body: (UnsafeMutableBufferPointer<TupleElement>) throws -> Result
    ) rethrows -> Result {
        try withUnsafeMutablePointer(to: &value) { tuplePtr in
            let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size
            
            return try tuplePtr.withMemoryRebound(
                to: TupleElement.self,
                capacity: count
            ) { elementPtr in
                try body(UnsafeMutableBufferPointer(start: elementPtr, count: count))
            }
            
        }
    }
}

var destinationTouple: (Int, Int, Int, Int) = (0, 0, 0, 0) // => (0, 0, 0, 0)
var sourceArray = Array(1...4)

print("before:", destinationTouple)

Tuple.withUnsafeMutableBufferPointer(to: &destinationTouple, element: Int.self) { (destBuffer: UnsafeMutableBufferPointer<Int>) -> Void in
    sourceArray.withUnsafeMutableBufferPointer { sourceBuffer in
    //  buffer[...] = 1...
        destBuffer[destBuffer.indices] = sourceBuffer[destBuffer.indices]
        return ()
    }
}

print("after:", destinationTouple) // => (1, 2, 3, 4)

推荐阅读