4

在带有 ios 6.1.3 的 iPhone 上,我正在尝试写入 outputStream,而没有 NSRunLoop。我的流只是通过以下方式初始化:

    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;
    }

然后,在代码的其他地方,当我尝试按如下方式传输数据时:

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];
}

'hasSpaceAvailable' 方法永远不会返回 true,因此代码卡住了。

为了发送数据,是否需要为输出流完成任何其他初始化任务?

4

1 回答 1

2

EASession 文档指出,您需要通过为其分配一个委托来配置流,该委托处理流事件并将其安排在运行循环中。

使用运行循环使您能够驱动流而无需担心线程。例如,如果您通过outputStream属性写入输出流,则很可能有一个内部输入流(绑定到公共可见输出流),EASession对象使用它来获取写入的字节。这个内部输入流(不可见)也可以使用与公开提供的输出流相同的运行循环outputStream

不要将内部输入流与公共输入流不匹配!所以基本上,有两个公共流和两个内部流。每个公共流在内部都有一个关联的挂件:输入流具有绑定的输出流,输出流具有绑定的输入流。

但是,您可以避免为您的(输出)流使用运行循环:您只需要保证该write:maxLength:方法在私有线程上执行,内部流不使用EASession.

你可以通过使用 dispatch来获取你的私有线程。你可以试试下面的代码:

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];
});

注意:如果先前的调用write:maxLength:返回零并且仍有数据要写入,这将阻塞线程。因此,内部流不能使用相同的线程,否则会出现死锁。

当线程被阻塞时,取消阻塞变得困难。也许,您应该尝试运行循环方法。

于 2013-11-04T16:13:46.410 回答