Это был долгий путь. Вот некоторые замечания по этому вопросу:
Вначале я отказался от идеи поддерживать и проверять оставшийся кэш, потому что это работало бы только для выходного потока, когда дальнейшие размышления предполагали, что входной поток также может быть заблокирован.
Вместо этого я настраиваю циклы холостого хода:
- (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…
Затем пришло время проверить отмену, инициированную пользователем, с помощью кнопки «отмена». Посередине синхронизации на стороне какао есть пауза, ожидающая ввода данных пользователем. Если пользователь отменяет в этот момент, приложение Какао закрывает потоки и удаляет их из цикла выполнения, поэтому я ожидал, что потоки на стороне другой соединения будут генерировать события NSStreamEventEndEncountered
или, возможно, NSStreamEventErrorOccurred
. Но нет, только одно событие произошло, NSStreamEventHasBytesAvailable
! Пойди разберись.
Конечно, на самом деле не было никаких «доступных байтов», поскольку поток был закрыт на стороне Какао, а не записан - таким образом, обработчик потока на стороне iOS вошел в бесконечный цикл. Не очень хорошо.
Затем я проверил, что произойдет, если одно из устройств перейдет в спящий режим. Во время паузы для пользовательского ввода я оставил iPhone в спящем режиме с помощью автоматической блокировки *, а затем предоставил пользовательский ввод на стороне какао. Снова сюрприз: приложение Cocoa продолжалось без помех до конца синхронизации, и когда я разбудил iPhone, приложение iOS оказалось также завершило свою сторону синхронизации.
Может быть, сбой на стороне iPhone был исправлен моей бездействующей петлей? Я добавил процедуру остановки сети, чтобы проверить:
if (![self receiveDataViaStream:(NSInputStream *)theStream])
[self stopNetwork]; // closes the streams, etc.
Синхронизация по-прежнему завершена. Икоты не было.
Наконец, я проверил, что произошло, если Mac (сторона какао) во время этой паузы засыпал для ввода. Это привело к некоторой обратной отрыжке: было получено два события NSStreamEventErrorOccurred
- на стороне Mac , после чего больше не было возможности записи в выходной поток. Никаких событий вообще не было получено на стороне iPhone, но если я проверил состояние потока iPhone, он вернул бы 5, NSStreamStatusAtEnd.
ВЫВОДЫ И ПЛАН:
- «Временный блок» - это что-то вроде единорога. Либо сеть работает без сбоев, либо вообще отключается.
- Если действительно существует такая вещь, как временный блок, нет способа отличить его от полного отключения. Единственными константами состояния потока, которые кажутся логичными для временного блока, являются
NSStreamStatusAtEnd
и NSStreamStatusError
. Но согласно приведенным выше экспериментам, они указывают на отключение.
- В результате чего я сбрасываю циклы while и выявляю отключение исключительно, проверяя bytesRead / Written <1. </li>
* iPhone никогда не будет спать, если он подчинен Xcode. Вы должны запустить его прямо с iPhone.