10

CFReadStreamReadストリーミング ファイル アップロードの一部として、が返されないという問題が発生しています。

これは iOS7 でのみ発生するようであり、シミュレーターよりも物理デバイスに対してデバッグする場合にはるかに頻繁に発生するか、少なくとも iOS7 でははるかに明白です。

ファイルのHTTP(またはHTTPS、問題はローカルでホストされているサーバーまたはリモートサーバーのいずれかで発生します)POSTを、直線のブロック(イベント駆動型ではない)CFNetwork呼び出しを介して行います。このハンドラーを呼び出す C コードの必要性です。コールバックの規定はありません。

それは良いことです。ネットワーク呼び出しはバックグラウンド スレッドおよび/または非同期ディスパッチを介して発生しています。

問題のネットワーク コードは次のようになります (簡潔にするためにエラー処理を削除しています)。

CFReadStreamRef upload = CFReadStreamCreateWithFile(
  kCFAllocatorDefault, upload_file_url);
CFRelease(upload_file_url);
CFReadStreamOpen(upload);

CFReadStreamRef myReadStream = CFReadStreamCreateForStreamedHTTPRequest(
  kCFAllocatorDefault, myRequest, upload);

CFReadStreamOpen(myReadStream);

CFIndex numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));

// etc.

単独では、このコードは iOS7 のすぐ下でハングすることを望んでいます。その前にいくつかの呼び出しを含むループを追加すると (途中でusleep確認します)、ほとんどの場合成功します。数百回試行するたびに失敗し、二度と戻りません。繰り返しますが、メイン スレッドは影響を受けません。CFReadStreamHasBytesAvailable

GMがこの振る舞いを片付けてくれることを望みましたが、まだ存在しています.

バイトを使用できるイベントを監視するために runloop/callback メソッドを追加しても効果はありません。呼び出しがハングしても、イベントは表示されません。

なぜこれが起こっているのか、またはそれを防ぐ方法について何か提案はありますか? CFReadStreamiOS 7 で別の動作を見ている人はいますか?

4

1 に答える 1

0

私はそのような厄介な回避策を試してみましたが、うまくいきます。問題は、サーバーからデルタ値を要求していることです。そのため、何か問題が発生した場合は、新しいデルタ値をフェッチするだけです。タイムアウトが発生することがあります)。少なくともこれにより、フォームの永続的なスレッドのブロックが防止され、何らかの方法でこの問題を処理する機会が与えられます。

NSInteger readStreamReadWorkaround(CFReadStreamRef readStrem, UInt8 *buffer, CFIndex bufferLength) {
  static dispatch_once_t onceToken;
  static BOOL isProblematicOs = YES;
  dispatch_once(&onceToken, ^{
    isProblematicOs = [[UIDevice currentDevice].systemName compare: @"7.0" options: NSNumericSearch]!=NSOrderedAscending;
  });

  NSInteger readBytesCount = -2;

  if (isProblematicOs) {
    CFStreamStatus sStatus = CFReadStreamGetStatus(readStrem);
    NSDate *date = [NSDate date];
    while (YES) {
      if(CFReadStreamHasBytesAvailable(readStrem)) {
        readBytesCount = CFReadStreamRead(readStrem, buffer, bufferLength);
        break;
      }
      sStatus = CFReadStreamGetStatus(readStrem);
      if (sStatus!=kCFStreamStatusOpen && sStatus !=kCFStreamStatusAtEnd
          || [date timeIntervalSinceNow]<-15.0) {
        break;
      }
      usleep(50000);
    }
  } else {
    readBytesCount = CFReadStreamRead(readStrem, buffer, sizeof(buffer));
  }
  return readBytesCount;
}

私はこの解決策が好きではありませんが、これまでのところ代替案はありません。

于 2013-10-04T12:57:12.550 に答える