1

我的 iOS 应用使用PGMidi(一个核心 MIDI 库)将 MIDI 库和程序更改发送到其他设备。一些用户报告说,消息有时会以错误的顺序到达——程序更改之后是银行更改。

对于每个银行/程序更改,我正在组装一个数值的 NSArray,然后将该数组传递给后台线程中的 sendMidiDataInBackground 方法:

int MSBStatus = 0xB0;
int MSBController = 0;
int MSBValue = 1;
NSArray *MSBValues = [NSArray arrayWithObjects:[NSNumber numberWithInt:MSBStatus], [NSNumber numberWithInt:MSBController], [NSNumber numberWithInt:MSBValue], nil];
[self performSelectorInBackground:@selector(sendMidiDataInBackground:) withObject:MSBValues];

int LSBStatus = 0xB0;
int LSBController = 32;
int LSBValue = 2;
NSArray *LSBValues = [NSArray arrayWithObjects:[NSNumber numberWithInt:LSBStatus], [NSNumber numberWithInt:LSBController], [NSNumber numberWithInt:LSBValue], nil];
[self performSelectorInBackground:@selector(sendMidiDataInBackground:) withObject:LSBValues];

int programStatus = 0xC0;
int programValue = 3
NSArray *programValues = [NSArray arrayWithObjects:[NSNumber numberWithInt:programStatus], [NSNumber numberWithInt:programValue], nil];
[self performSelectorInBackground:@selector(sendMidiDataInBackground:) withObject:programValues];

sendMidiDataInBackground 方法将值更改为 C 数组并将它们传递给 PGMidi 的 sendBytes 方法,该方法将它们组装成一个数据包列表并通过 MIDISend 发送出去。我注意到时间戳设置为 0,这意味着“现在”:

- (void) sendBytes:(const UInt8*)bytes size:(UInt32)size {
    Byte packetBuffer[size+100];
    MIDIPacketList *packetList = (MIDIPacketList*)packetBuffer;
    MIDIPacket     *packet     = MIDIPacketListInit(packetList);
    packet = MIDIPacketListAdd(packetList, sizeof(packetBuffer), packet, 0, size, bytes);
    OSStatus s = MIDISend(midi.outputPort, endpoint, packetList);
}

但在某些时候,显然有些消息被延迟了,所以它们以错误的顺序结束。这是因为后台线程没有按照它们开始的顺序完成吗?如果是这样,我可以组合 MSB、LSB 和程序数组并将组合数组发送到 sendMidiDataInBackground,而不是启动三个单独的线程,这应该可以解决它。

或者这可能在调用 MIDISend 函数之后发生?如果是这样,我需要另一个解决方案。

我不能在自己的测试中重复这个问题,所以我想确定问题是什么,这样我就有更好的机会实际修复它。

4

1 回答 1

0

根据文档-performSelectorInBackground:withObject:创建一个新的后台线程。您不应该对操作系统将如何调度这些线程做出任何假设。您不能指望它们按照您创建它们的顺序运行。

是什么让您认为您需要在后台执行此操作?发送一些简短的 MIDI 消息不太可能在很长一段时间内阻塞您的主线程。创建三个单独的线程对于少量工作来说是一个令人难以置信的开销。

如果您确实需要在后台执行此操作,请考虑使用 GCDdispatch_asyncNSOperation带有串行队列的东西,和/或在一个方法调用而不是三个方法调用中完成所有工作。

于 2012-06-20T04:02:00.260 回答