First, it's not good to schedule your stream on the main runloop - especially on standard mode.
In such setup case, holding a menu open, or dragging event of a file on the desktop, or any lengthy UI event handling actually, will block the runloop mode temporarily and starve your stream.
You should, indeed use a secondary thread for handling the stream. I'm trying now to do something similar to you - handle my stream from an NSOperation (which always runs in some unknown thread's context), but I found this discouraging paragraph in Apple's "Stream Programming Guide"
Before you open the stream to begin the streaming of data, send a
scheduleInRunLoop:forMode: message to the stream object to schedule it
to receive stream events on a run loop. By doing this, you are helping
the delegate to avoid blocking when there is no data on the stream to
read. If streaming is taking place on another thread, be sure to
schedule the stream object on that thread’s run loop. You should never
attempt to access a scheduled stream from a thread different than the
one owning the stream’s run loop. Finally, send the NSInputStream
instance an open message to start the streaming of data from the input
source.
Now rescheduling the stream on the current operation's thread runloop, and running it... seems a huge overhead, and I'm not sure NSStream can handle rescheduling too frequently.
I don't know what is best to do about this, but I'm testing and studying, and will update as soon as I can.
You can, of course, create a special thread for the stream, and from your operation - synchronously call on that thread all access to the stream.