2

現在のデザインでは、フォルダー構造を表すテーブルビューがあります。ユーザーがセルをタップするとAFHTTPRequestOperation、ファイルをダウンロードするためのanが作成されます。セルが現在のダウンロード状態(none / downloaded / downloading)を示している間に、ファイルがダウンロードされます。

ダウンロード状態はNSManagedObject、各セルに対応するに設定されます。ダウンロードの完了ブロックで、ダウンロード状態を「ダウンロード済み」フラグに設定しました。これに伴う問題は、ユーザーが現在のテーブルビューデータから別のデータに移動すると、競合ブロックが間違って設定されることです。NSManagedObjectこれは、に基づいてルックアップを実行しますNSIndex

AFHTTPRequestOperation一言で言えば、完了時に操作を実行できるように、オブジェクトを一緒に渡す方法を知りたいと思います。NSPredicateintやstringのように単純で、この値に基づいてリクエストを実行できます。

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
        [self.operations addObject:operation];
        [self.inProgressDownloads addObject:indexPath];
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *extension = [[self.selectedFile.name componentsSeparatedByString:@"."] lastObject];
        NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat: @"%@.%@", self.selectedFile.item_id, extension]];
        operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
        self.selectedFile.status = DOWNLOADING;
        [self.tableView beginUpdates];
        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
        [self.tableView endUpdates];

        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            NSLog(@"File downloaded to: %@", path);
            self.selectedFile.status = DOWNLOADED;
            self.selectedFile.is_stored = @YES;
            [self.tableView beginUpdates];
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
            [self.tableView endUpdates];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"Error: %@", error);
            self.selectedFile.status = DOWNLOAD_ERROR;
        }];

        [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
            dispatch_async(dispatch_get_main_queue(), ^{
                float percent = (float)totalBytesRead / (float)totalBytesExpectedToRead;
                NSLog(@"totalBytesExpectedToRead %d", (int)(percent * 100));
            });
        }];

        [operation start];
4

1 に答える 1

3

一言で言えば、AFHTTPRequestOperationと一緒にオブジェクトを渡して、完了時に操作を実行できるようにする方法を知りたいと思います。これはintまたはstringのように単純であり、この値に基づいてNSPredicate要求を実行できます。

ここで、クロージャ/ブロックの力が発揮されます。特別なものをブロックに渡す必要はありません。ブロック内で字句的に表示されている任意のオブジェクトを参照でき、ブロックの実行時に使用可能になります。

Appleドキュメントから(具体的には、ポイント2):

ブロックは通常、小さな自己完結型のコードを表します。そのため、これらは、同時に実行される可能性のある作業単位をカプセル化する手段として、またはコレクション内のアイテムに対して、または別の操作が終了したときのコールバックとして特に役立ちます。

ブロックは、次の2つの主な理由から、従来のコールバック関数の便利な代替手段です。

  1. これらを使用すると、メソッド実装のコンテキストで後で実行される呼び出しの時点でコードを記述できます。
    したがって、ブロックは多くの場合、フレームワークメソッドのパラメータです。

  2. ローカル変数へのアクセスを許可します。
    操作を実行するために必要なすべてのコンテキスト情報を具体化するデータ構造を必要とするコールバックを使用するのではなく、ローカル変数に直接アクセスするだけです。

私があなたがやろうとしていることを正しく理解していれば、これはうまくいくはずです:

TYPE_HERE* localSelectedFile = self.selectedFile;

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"File downloaded to: %@", path);
        localSelectedFile.status = DOWNLOADED;
        localSelectedFile.is_stored = @YES;
        [self.tableView beginUpdates];
        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone];
        [self.tableView endUpdates];
       ...

ここで、実行さself.selectedFileれた時点での値をローカル変数に格納しています。operation次に、そのローカル変数をブロック本体に使用しています。これは合法であり(これは私が言及していたクロージャの力です。クロージャは実行コンテキストに関する情報を保持します)、処理しているオブジェクトへの参照を提供します。

全体像としては、これが興味深いと思うかもしれません。

于 2013-01-15T15:16:59.823 に答える