3

NSOperationのサブクラスを使用して、AmazonのiOS SDK(v1.3.2)を使用して大きなファイルをAWSS3にアップロードします。これはすべて正常に機能しますが、一部のベータテスターはデッドロックを経験します(iOS5.1.1)。その結果、一度に1つの操作しか実行できないため、操作がスケジュールされているNSOperationQueueがブロックされます。問題は、ベータテスターが毎回この問題を経験するのに対し、私は問題を再現できないことです。

AWS iOS SDKの動作方法により、操作は非常に複雑です。ただし、テストに基づいて私が知る限り、この問題はAWSiOSSDKとは関係ありません。操作の主な方法を以下に貼り付けます。操作の主な方法のアイデアは、このStackOverflowの質問に基づいています。

- (void)main {
    // Operation Should Terminate
    _operationShouldTerminate = NO;

    // Notify Delegate
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.delegate operation:self isPreparingUploadWithUuid:self.uuid];
    });

    // Increment Network Activity Count
    [self incrementNetworkActivityCount];

    // Verify S3 Credentials
    [self verifyS3Credentials];

    while (!_operationShouldTerminate) {
        if ([self isCancelled]) {
            _operationShouldTerminate = YES;

        } else {
            // Create Run Loop
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
    }

    // Decrement Network Activity Count
    [self decrementNetworkActivityCount];

    NSLog(@"Operation Will Terminate");
}

マルチパートアップロードを終了するメソッドは、ブール値_operationShouldTerminateを設定しYESて操作を終了します。その方法は次のようになります。

- (void)finalizeMultipartUpload {
    // Notify Delegate
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.delegate operation:self didFinishUploadingUploadWithUuid:self.uuid];
    });

    // Operation Should Terminate
    _operationShouldTerminate = YES;

    NSLog(@"Finalize Multipart Upload");
}

最終ログステートメントはコンソールに出力されますが、操作のmainメソッドの最終ログステートメントがコンソールに出力されないため、mainメソッドのwhileループは終了していないようです。その結果、操作がスケジュールされている操作キューがブロックされ、スケジュールされた操作は実行されません。

操作のisFinishedメソッドは、以下のように単純に戻り_operationShouldTerminateます。

- (BOOL)isFinished {
    return _operationShouldTerminate;
}

whileループが終了しないのは奇妙なことであり、私自身のテストデバイス(iPhone 3GS、iPad 1、およびiPad 3)のいずれでも発生しないのはさらに奇妙なことです。ヘルプやポインタは大歓迎です。

4

2 に答える 2

2

問題の解決策は、結局のところ複雑で単純です。私が間違って想定したのは、操作のメソッドとデリゲートコールバックが同じスレッド、つまり操作のmainメソッドが呼び出されたスレッドで実行されたということでした。これは常に当てはまるわけではありません。

これは私のテストとデバイス(iPhone 3GS)で当てはまりましたが、それが私自身が問題を経験しなかった理由です。mainただし、私のベータテスターはマルチコアプロセッサ(iPhone 4 / 4S)を搭載したデバイスを使用していたため、操作のメソッドが呼び出されたスレッドとは異なるスレッドでコードの一部が実行されました。

この結果、間違ったスレッド_operationShouldTerminateのメソッドで変更されました。finalizeMultipartUploadこれはwhile、メソッドのループがmain適切に終了せず、操作がデッドロックしたことを意味します。

要するに、解決策は、メソッドが呼び出され_operationShouldTerminateたのと同じスレッドで更新することです。これにより、ループmainが適切に終了し、操作が終了します。while

于 2012-09-12T10:04:29.760 に答える
1

コードには多くの問題があり、2つの解決策を提供できます。

1)Appleの並行性プログラミングガイドの並行NSOperationsを読んでください。runLoopを「有効」に保つには、ポートを追加するか、タイマーをスケジュールする必要があります。自動解放プールを取得できない可能性があるため、メインループには自動解放プールが含まれている必要があります(同じメモのメモリ管理を参照)。操作が終了したときにoperationQueueに通知するには、KVOを実装する必要があります。

2)または、フィールドテスト済みの強化コードを少量採用して再利用することもできます。そのXcodeプロジェクトには、関心のある3つのクラスが含まれています。上記で達成しようとしていることをうまく実行するConcurrentOperationファイルです。Webfetcher.mクラスは、Webから非同期URLフェッチを実行するために、並行操作をサブクラス化する方法を示しています。また、OperationsRunnerは、操作キュー(実行、キャンセル、クエリなど)を管理するために、あらゆる種類のクラスに追加できる小さなヘルパーファイルです。上記はすべて100行未満のコードであり、コードを機能させるための基盤を提供します。OperationsRunner.hファイルには、「方法」も記載されています。

于 2012-09-11T18:00:15.773 に答える