Pergunta

I have written a small application, initially under OSX 10.8, that receives MIDI events via MidiEventCallback and puts the data into a NSMutableArray that is a member of a NSTableViewDataSource.

In this video you can see how it worked without any problems on OSX 10.8.

Now I have a new MacBook that runs on OSX 10.9, installed XCode and got all my project files and compiled the application.

Have connected my MIDI controller to my MacBook, started the application and pressing keys on the MIDI controller.

The problem:

  • The NSTableView is not being updated as it should. If I press my piano keys, no MIDI messages will be displayed and after a couple of seconds I get an exception. Here is a screenshot of what XCode is showing me then:

Exception when playing my MIDI piano without resizing the window of my application.

  • I stop the application and start it again. Now, when pressing keys, I resize the application window continuously and the NSTableView does update properly, no exception, everything fine.
  • Same when I press some piano keys a couple of times. Then bring some other application to the front and then my application to the front again. Again, all MIDI messages are displayed properly in my NSTableView.

Any idea what this can be? Is it a OSX 10.9 related issue or could it be with changing to a new MacBook. Am running out of options.

What I have tried is connecting the NSWindow of my application as an IBOutlet to my controller that acts as a NSTableViewDataSource and tried the following calls right after I did [tableView reloadData]

  • [window update]
  • [window display]
  • [window flushWindow]

but nothing helped. Any help highly appreciated.

EDIT

Did some more debugging following the comments and actually was looking at the wrong place.

Here some code for more context:

My controller has a property called MidiEventListener that receives all MIDI events and puts them into eventList.

@interface MidiAidController()
  ...
  @property NSMutableArray *eventList;
  @property MidiEventListener* listener;
@end

In the init method of my controller I do the following

_eventList = [[NSMutableArray alloc] init];
MidiEventCallback eventCallback = ^(MidiEvent* midiEvent)
{
  [[self eventList] addObject:midiEvent];
  [[self tableView] reloadData];
};
...
self.listener = [[MidiEventListener alloc] initWithCallback:eventCallback];

In MidiEventListener, within initWithCallback, the following happens:

result = MIDIInputPortCreate(_midiClient, CFSTR("Input"), midiInputCallback, (__bridge_retained void *)(self), &_inputPort);

Now, let's go over to midiInputCallback:

static void midiInputCallback(const MIDIPacketList* list, void *procRef, void *srcRef)
{
  MidiEventListener *midiEventListener = (__bridge MidiEventListener*)procRef;
  @autoreleasepool {
    const MIDIPacket *packet = &list->packet[0];

    for (unsigned int i = 0; i < list->numPackets; i++)
    {
        MidiEvent* midiEvent = [[MidiEvent alloc] initWithPacket:packet];
        midiEventListener.midiEventCallback(midiEvent);
        packet = MIDIPacketNext(packet);
    }
  }
}

That is basically it. The Exception happens at midiEventListener.midiEventCallback(midiEvent);. I always looked at *[tableView reloadData] since that was the line when clicking under Thread 6 - 19__25... (see screenshot above). But when I click on Thread 6 - 20 midiInputCallback then I get this line highlighted.

SOLUTION

Reloading the data has to be done from the main thread:

MidiEventCallback eventCallback = ^(MidiEvent* midiEvent)
{
  [[self eventList] addObject:midiEvent];
  dispatch_async(dispatch_get_main_queue(), ^(void){[[self tableView] reloadData];});
};
Foi útil?

Solução

*Thread 6 - 19__25...* and reloadData

call reload only on Main Thread

e.g.

void MyCallback(...) {
    dispatch_async(dispatch_get_main_queue(), ^{
        ...
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top