Question

On an iPhone, with ios 6.1.3, I'm trying to write to an outputStream, without an NSRunLoop. My stream is simply initialized by:

    session = [[EASession alloc] initWithAccessory:accessory
                                       forProtocol:protocolString];
    if (session)
    {
        NSLog(@"opening the streams for this accessory");
        [[session inputStream] open];
        [[session outputStream] open];
        [session retain];
        streamReady = true;
        receivedAccPkt = true;
    }

Then, elsewhere in the code, when I try to transmit data as follows:

uint8_t requestData[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
while (![[eas outputStream] hasSpaceAvailable]);
@synchronized(self) {
    len += [[eas outputStream] write:requestData maxLength:8];
}

The 'hasSpaceAvailable' method never returns true, so the code is stuck.

Are there any other initialisation tasks to be done for an output stream, in order to send data?

Was it helpful?

Solution

The EASession documentation states that you need to configure the streams by assigning it a delegate which handles the stream events and schedule it in a run loop.

Using a run loop enables you to drive the streams without worrying about threads. For example, if you write into the output stream via the outputStream property, there's very likely an internal input stream (bound to the public visible output stream) which is used by the EASession object to obtain the bytes written. This internal input stream (which is not visible) may also use the same run loop as the publicly provided output stream outputStream.

Don't mismatch the internal input stream with the public input stream! So basically, there are two public streams and two internal streams. Each public stream has an associated pendant internally: a input stream has a bound output stream, and an output stream has a bound input stream.

You can however, avoid using a run loop for your (output) stream: you just need to guarantee that the write:maxLength: method is executed on a private thread, which is not used by the internal streams by EASession.

You can get your private thread just by utilizing dispatch. You may try the code below:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    [outputStream open];
    const char* data = ...;
    int dataLength = ...;
    while (dataLength && !isCancelled) {
        int written = [outputStream write:(const uint8_t*)data maxLength:1];
        if (written > 0) {
             dataLength -= written;
             data += written;
        }
        else if (written < 0 )
        {
            // error occurred
            break;
        }
    }
    [outputStream close];
});

Note: this will block the thread if a previous call to write:maxLength: returned zero and if there is still data to write. Thus, the internal streams must not use the same thread, otherwise you get a dead lock.

When the thread is blocked, it becomes difficult to cancel the block. Perhaps, you should try a run loop approach.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top