这是一个漫长的过程。以下是对此问题的一些后续行动:
早些时候,我放弃了维护和检查剩余缓存的想法,因为这仅适用于输出流,而进一步的反射表明输入流也可能被阻塞。
相反,我设置了空闲的while循环:
- (void) stream:(NSStream *)theStream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode)
// RECEIVING
case NSStreamEventHasBytesAvailable: {
if (self.receiveStage == kNothingToReceive)
return;
// Get the data from the stream. (This method returns NO if bytesRead < 1.)
if (![self receiveDataViaStream:(NSInputStream *)theStream]) {
// If nothing was actually read, consider the stream to be idling.
self.bStreamIn_isIdling = YES;
// Repeatedly retry read, until (1) the read is successful, or (2) stopNetwork is called, which will clear the idler.
// (Just in case, add nil stream property as a loop breaker.)
while (self.bStreamIn_isIdling && self.streamIn) {
if ([self receiveDataViaStream:(NSInputStream *)theStream]) {
self.bStreamIn_isIdling = NO;
// The stream will have started up again; prepare for next event call.
[self assessTransmissionStage_uponReadSuccess];
}
}
}
else
// Prepare for what happens next.
[self assessTransmissionStage_uponReadSuccess];
break;
// SENDING
case NSStreamEventHasSpaceAvailable:
if (self.sendStage == kNothingToSend)
return;
if (![self sendDataViaStream:(NSOutputStream *)theStream]) {
self.bStreamOut_isIdling = YES;
while (self.bStreamOut_isIdling && self.streamOut) {
if ([self sendDataViaStream:(NSOutputStream *)theStream]) {
self.bStreamOut_isIdling = NO;
[self assessTransmissionStage_uponWriteSuccess];
}
}
}
else
[self assessTransmissionStage_uponWriteSuccess];
break;
// other event cases…
然后是时候通过“取消”按钮测试用户发起的取消了。在同步的中途,Cocoa 端有一个暂停,等待用户输入。如果用户此时取消,Cocoa 应用程序会关闭流并将它们从运行循环中删除,所以我预计连接另一端的流会生成NSStreamEventEndEncountered
事件,或者可能是NSStreamEventErrorOccurred
. 但是,不,只有一个事件发生了,一个NSStreamEventHasBytesAvailable
!去搞清楚。
当然,实际上并没有任何“可用字节”,因为流已经在 Cocoa 端关闭,而不是写入——所以 iOS 端的流处理程序进入了无限循环。不太好。
接下来我测试了如果其中一个设备进入睡眠状态会发生什么。在用户输入暂停期间,我让 iPhone 通过 auto-lock* 进入睡眠状态,然后在 Cocoa 端提供用户输入。再次惊喜:Cocoa 应用程序一直没有受到干扰,直到同步结束,当我唤醒 iPhone 时,iOS 应用程序证明也完成了同步。
我的空闲循环修复了 iPhone 端的打嗝吗?我投入了一个停止网络例程来检查:
if (![self receiveDataViaStream:(NSInputStream *)theStream])
[self stopNetwork]; // closes the streams, etc.
同步仍然运行到完成。没有打嗝。
最后,我测试了如果Mac(Cocoa 端)在输入暂停期间进入睡眠状态会发生什么。这产生了一种向后的打嗝:在MacNSStreamEventErrorOccurred
端接收到两个事件,之后不再可能写入输出流。iPhone 端根本没有收到任何事件,但是如果我测试 iPhone 的流状态,它将返回 5,NSStreamStatusAtEnd。
结论与计划:
- “临时区块”有点像独角兽。网络要么运行顺畅,要么完全断开连接。
- 如果真的有临时阻塞这样的东西,那就没有办法将它与完全断开区分开来。对于临时块来说,唯一看起来合乎逻辑的流状态常量是
NSStreamStatusAtEnd
和NSStreamStatusError
。但是根据上述实验,这些表明断开连接。
- 结果,我丢弃了 while 循环,并且仅通过检查 bytesRead/Written < 1 来检测断开连接。
*如果 iPhone 受制于 Xcode,它将永远不会休眠。您必须直接从 iPhone 运行它。