0

Reading the documentation on InputStream it seems like it should be a matter of setting a delegate on the InputStream, scheduling the InputStream, and calling open to start events firing, but it seems like this doesn't happen without calling run on RunLoop.current, which then runs without returning.

How do I allow the run call to return?

Here is my sample code:

import Foundation

let data : Data = "this is a test".data(using: String.Encoding.utf8)!

let inputStream : InputStream = InputStream(data: data)

class TestStreamDelegate: NSObject, StreamDelegate {
    static let CAPACITY = 8 * 1024
    let inputStream : InputStream
    var buffer : UnsafeMutablePointer<UInt8>
    init(inputStream: InputStream) {
        self.inputStream = inputStream
        self.buffer = UnsafeMutablePointer
            .allocate(capacity: TestStreamDelegate.CAPACITY)
    }

    public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
        switch (eventCode) {
        case Stream.Event.openCompleted:
            break
        case Stream.Event.hasBytesAvailable:
            if aStream == inputStream {
                let read = inputStream.read(self.buffer,
                                            maxLength: TestStreamDelegate.CAPACITY)
                let str =
                    String(bytesNoCopy: UnsafeMutableRawPointer(self.buffer),
                           length: read,
                           encoding: String.Encoding.utf8,
                           freeWhenDone: false)
                print(str!)
            }
        case Stream.Event.hasSpaceAvailable:
            break
        case Stream.Event.errorOccurred:
            break
        case Stream.Event.endEncountered:
            if aStream == inputStream {
                inputStream.close()
                inputStream.remove(from: RunLoop.current,
                                   forMode: RunLoopMode.defaultRunLoopMode)
            }
        default:
            print("Received \(eventCode.rawValue)")
        }
    }
}

var testDelegate = TestStreamDelegate(inputStream: inputStream)

inputStream.delegate = testDelegate
inputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
inputStream.open()

RunLoop.current.run()

// Following line never executes:
print("Finished")
Julian
  • 2,837
  • 17
  • 15
  • You schedule the stream to receive events on a run loop. That requires the run loop to run. What is the actual problem? – Martin R Jun 24 '17 at 16:41
  • I'd like to get control back to continue on, or understand the right idiom to employ for reading from a stream. Updated my question to try to clarify that. – Julian Jun 24 '17 at 16:52
  • 1
    You can run the runloop until some condition is satisfied, see https://stackoverflow.com/a/25126900/1187415 for an example. – Martin R Jun 24 '17 at 16:56
  • Yes thank you - I'm able to apply what you wrote there to this. Specifically I added a done flag to the delegate which gets set on the end event and is checked. I don't think the documentation I linked to is as clear/complete as it should be. – Julian Jun 24 '17 at 17:02

0 Answers0