OK, after messing around for a while I've worked it out. I will do my best to explain, and if there are any errors in this info, I hope some experts feel free to chime in.
There are two ways to receive MIDI messages with Core MIDI. Either you create a MIDIPortRef as an input port with MIDIInputPortCreate, and then iterate over all possible sources, connecting with each one in turn with MIDIPortConnectSource. Or you can just create a MIDIEndpointRef as a MIDI destination with MIDIDestinationCreate - then there is no need to iterate over all the sources, and in both cases a MIDIReadProc is needed - i.e. the function you will use to read the incoming messages has exactly the same signature in both scenarios.
When you use MIDIDestinationCreate, your app shows up in other apps as a destination which can be selected. This makes much more sense than selecting input sources within your app, especially since at any given time these sources may or may not exist. But it also relies on the other app being able to select yours as a destination. Maybe both things are needed, to cover all scenarios.
I did not find any example code using MIDIDestinationCreate for inter-app communication on iOS, so I hope this info is of some use.
Anyway beware that your app needs to be set up for background audio, as per this question: