Search code examples
xamarin.iosiphoneexternalinterface

handling NSStream events when using EASession in MonoTouch


Does anyone have an example of how to handle read and write NSStream events in Monotouch when working with accessories via EASession?

It looks like there isn't a strongly typed delegate for this and I'm having trouble figuring out what selectors I need to handle on the delegates of my InputStream and OutputStream and what I actually need to do with each selector in order to properly fill and empty the buffers belonging to the EASession object.

Basically, I'm trying to port Apple's EADemo app to Monotouch right now.

Here's the Objective-C source that I think is relevant to this problem:

/

/ asynchronous NSStream handleEvent method
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    switch (eventCode) {
        case NSStreamEventNone:
            break;
        case NSStreamEventOpenCompleted:
            break;
        case NSStreamEventHasBytesAvailable:
            [self _readData];
            break;
        case NSStreamEventHasSpaceAvailable:
            [self _writeData];
            break;
        case NSStreamEventErrorOccurred:
            break;
        case NSStreamEventEndEncountered:
            break;
        default:
            break;
    }
}
/ low level write method - write data to the accessory while there is space available and data to write
- (void)_writeData {
    while (([[_session outputStream] hasSpaceAvailable]) && ([_writeData length] > 0))
    {
        NSInteger bytesWritten = [[_session outputStream] write:[_writeData bytes] maxLength:[_writeData length]];
        if (bytesWritten == -1)
        {
            NSLog(@"write error");
            break;
        }
        else if (bytesWritten > 0)
        {
             [_writeData replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
        }
    }
}

// low level read method - read data while there is data and space available in the input buffer
- (void)_readData {
#define EAD_INPUT_BUFFER_SIZE 128
    uint8_t buf[EAD_INPUT_BUFFER_SIZE];
    while ([[_session inputStream] hasBytesAvailable])
    {
        NSInteger bytesRead = [[_session inputStream] read:buf maxLength:EAD_INPUT_BUFFER_SIZE];
        if (_readData == nil) {
            _readData = [[NSMutableData alloc] init];
        }
        [_readData appendBytes:(void *)buf length:bytesRead];
        //NSLog(@"read %d bytes from input stream", bytesRead);
    }

    [[NSNotificationCenter defaultCenter] postNotificationName:EADSessionDataReceivedNotification object:self userInfo:nil];
}

I'd also appreciate any architectural recommendations on how to best implement this in monotouch. For example, in the Objective C implementation these functions are not contained in any class--but in Monotouch would it make sense to make them members of my


Solution

  • It looks like the latest version of MonoTouch (I had to upgrade to iOS 4.2 first to get it) now implements a strongly typed delegate for HandleEvent and a new NSStreamEvent type so it can be more easily handled:

    // asynchronous NSStream handleEvent method
    public override void HandleEvent (NSStream theStream, NSStreamEvent streamEvent)
    {
        switch (streamEvent) 
        {
            case NSStreamEvent.None:
                break;
            case NSStreamEvent.OpenCompleted:
                break;
            case NSStreamEvent.HasBytesAvailable:
                LowReadData((NSInputStream)theStream);
                break;
            case NSStreamEvent.HasSpaceAvailable:
                LowWriteData((NSOutputStream)theStream);
                break;
            case NSStreamEvent.ErrorOccurred:
                break;
            case NSStreamEvent.EndEncountered:
                break;
            default:
                break;
        }
    }