AudioToolbox 框架将MIDIMetaEvent 定义为
typedef struct MIDIMetaEvent
{
UInt8 metaEventType;
UInt8 unused1;
UInt8 unused2;
UInt8 unused3;
UInt32 dataLength;
UInt8 data[1];
} MIDIMetaEvent;
其中data[1] 实际上用作“可变长度数组”。
在(Objective-)C 中,可以只分配一个指向内存块的指针
实际需要的尺寸:
MIDIMetaEvent *mep = malloc(sizeof(MIDIMetaEvent) + data.count);
Swift 对指针强制转换更加严格,固定大小的数组映射到
Swift 元组(处理起来很麻烦)。
以下实用程序类显示了如何解决此问题:
class MyMetaEvent {
private let size: Int
private let mem : UnsafeMutablePointer<UInt8>
let metaEventPtr : UnsafeMutablePointer<MIDIMetaEvent>
init(type: UInt8, data: [UInt8]) {
// Allocate memory of the required size:
size = sizeof(MIDIMetaEvent) + data.count
mem = UnsafeMutablePointer<UInt8>.alloc(size)
// Convert pointer:
metaEventPtr = UnsafeMutablePointer(mem)
// Fill data:
metaEventPtr.memory.metaEventType = type
metaEventPtr.memory.dataLength = UInt32(data.count)
memcpy(mem + 8, data, UInt(data.count))
}
deinit {
// Release the allocated memory:
mem.dealloc(size)
}
}
然后你可以创建一个实例
let me = MyMetaEvent(type: 0x7F, data: myData)
并将me.metaEventPtr 传递给采用UnsafePointer<MIDIMetaEvent> 的Swift 函数
论据。
Swift 3/4 更新:
不再可能简单地将指针转换为不同的类型,
一定是“反弹”:
class MyMetaEvent {
private let size: Int
private let mem: UnsafeMutablePointer<UInt8>
init(type: UInt8, data: [UInt8]) {
// Allocate memory of the required size:
size = MemoryLayout<MIDIMetaEvent>.size + data.count
mem = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
mem.initialize(to: 0, count: size)
// Fill data:
mem.withMemoryRebound(to: MIDIMetaEvent.self, capacity: 1) { metaEventPtr in
metaEventPtr.pointee.metaEventType = type
metaEventPtr.pointee.dataLength = UInt32(data.count)
memcpy(&metaEventPtr.pointee.data, data, data.count)
}
}
deinit {
// Release the allocated memory:
mem.deallocate(capacity: size)
}
func withMIDIMetaEventPtr(body: (UnsafePointer<MIDIMetaEvent>) -> Void) {
mem.withMemoryRebound(to: MIDIMetaEvent.self, capacity: 1) { metaEventPtr in
body(metaEventPtr)
}
}
}
使用自定义数据创建实例:
let me = MyMetaEvent(type: 0x7F, data: ...)
传递给采用UnsafePointer<MIDIMetaEvent> 参数的函数:
me.withMIDIMetaEventPtr { metaEventPtr in
let status = MusicTrackNewMetaEvent(track, 0, metaEventPtr)
}