我的iOS应用程序使用核心MIDI库PGMidi将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函数后会发生这种情况吗?如果是这样,我需要另一种解决方案。
我不能在自己的测试中重复这个问题,所以我想知道问题是什么,所以我有更好的机会实际修复它。
答案 0 :(得分:0)
根据the documentation,-performSelectorInBackground:withObject:
创建了一个新的后台线程。您不应该对操作系统如何安排这些线程做出任何假设。您不能指望它们按照您创建它们的顺序运行。
是什么让你认为你需要在后台执行此操作?发送一些简短的MIDI信息不太可能在很长一段时间内阻止你的主线程。创建三个独立的线程对于少量工作来说是一笔令人难以置信的开销。
如果您确实需要在后台执行此操作,请考虑使用GCD的dispatch_async
或NSOperation
之类的串行队列,和/或在一次方法调用中完成所有工作而不是三次