1

PDFファイル、ページに保存する情報を生成するために、保存されたデータをループしてロードする必要があるアプリがあります。ループを作成しましたが、いわば実行速度が速すぎます。保存されたページは十分に速くロードできないため、結果のデータは不完全です。遅延または完了ハンドラーを使用して for ループを作成する必要があると思います。何かのようなもの:

for (int i = 0, i < numberOfPages, doTaskWithCompletion:i++) {
    arrayOfPages = [self loadDataAtIndex:i withCompletionHandler:handler];
    [self writeDataToFile:arrayOfPages];
}

その疑似コードの書き方さえわかりませんが、基本的には、データをロードするタスクのために完了ハンドラーが起動した後に次の反復にジャンプしたいだけです。

注: ソース データはコア データから取得され、PDF ファイルとして保存されます。データは、ページのページとビューです。各ページには、1 つまたは無制限のビューを含めることができます。各ビューには、画像などのデータも含まれる場合があります。現在何が起こっているかというと、書き込まれたページ数は正しいですが、PDF が書き込まれる前にページが読み込まれないため、すべて同じデータを読み取るため、PDF にレンダリングされたページのビューは同一です。

4

2 に答える 2

1

次のように問題にアプローチできます。

最初に汎用完了ブロック型を定義します。パラメータの結果は何でもよいことに注意してください。これが の場合NSErrorは失敗を示し、そうでない場合は成功を示します。

typedef void (^completion_t)(id result);

非同期タスクのブロック タイプを定義します。タスクは入力としてインデックスを受け取り、- 非同期であるため、最後のパラメーターとして完了ブロックを受け取ります。

typedef void (^unary_async_t)(int index, completion_t completion);

タスク ブロック オブジェクトは次のように定義できます

unary_async_t task = ^(int index, completion_t completion) {
    [self loadDataAtIndex:index withCompletion:^(id result){
        if (![result isKindOfClass:[NSError class]]) {
            [self writeDataToFile:result];
            result = @"OK";
        }
        if (completion) {
            completion(result);
        }
    }];
};

注: あなたloadDataAtIndex:withCompletion:は非同期であるため、最後のパラメーターとして完了ブロックを受け取ります。完了ブロックのパラメーター結果は、非同期タスクの結果、つまり「ページの配列」またはNSErrorそれが失敗した場合のオブジェクトです。

この完了ブロックでは、結果 (ページ) をディスクに保存し、 を呼び出しwriteDataToFile:ます。(これは失敗しないと仮定しています)。それがすべて終了した場合、タスクは提供された完了ブロックの完了(nil でない場合) を呼び出して、操作全体の結果を渡します。これは、成功の場合は @"OK"、NSError失敗の場合は です。

ここで、より興味深い部分: 多数の _task_s が順番に次々に実行されるループでこれを作成する方法:

2 つのヘルパー メソッドまたは関数を定義します。

最後に必要なのは、次のシグネチャを持つ関数です。

void apply_each_with_range(int lowerBound, int upperBound, 
                           unary_async_t task, completion_t completion);

これは、タスクをN 回呼び出す関数であり、 lowerBound (含む) からupperBound (含まない) までの範囲のパラメーターインデックスを渡します。ここで、 NはupperBound - lowerBoundに等しく、インデックスはlowerBoundで始まります。

これは非同期関数であるため、最後のパラメーターとして完了ブロックを受け取ります。繰り返しますか?さて、あなたはパターンを認識する必要があります!;)

実装は次のとおりです。

void apply_each_with_range(int lowerBound, int upperBound, 
                           unary_async_t task, completion_t completion)
{
    do_apply(lowerBound, upperBound, task, completion);
}

そして、もう 1 つのヘルパー - 最終的に何らかの " for_each index in range[upperBound, lowerBound] パラメーターインデックスを使用してタスクを順次呼び出します"を実行します。

static void do_apply(int index, int upperBound, 
                     unary_async_t task, completion_t completion)
{
    if (index >= upperBound) {
        if (completion)
            completion(@"OK");
        return;
    }
    task(index, ^(id result) {
        if (![result isKindOfClass:[NSError class]]) {
            do_apply(index + 1, upperBound, task, completion);
        }
        else {
            // error occurred: stop iterating and signal error
            if (completion) {
                completion(result);
            }
        }
    });
}

この関数do_applyは、最初にインデックスが範囲外かどうかをチェックします。終了した場合は、@"OK" を使用して完了ハンドラーを呼び出します。それ以外の場合は、引数indexを使用してtaskを呼び出し、タスクの終了時に呼び出される完了ハンドラーを提供します。この完了ハンドラー自体がタスクの結果を渡します。成功した場合は、引数のインデックスを 1 つ増やして自身を呼び出します。これは「再帰」のように見えるかもしれませんが、そうではありません。それ自体を呼び出すときに、すでに返されています。do_applydo_apply

タスクが返されてエラーが発生した場合は停止し、完了ハンドラー (最終的に呼び出しサイトによって提供される) でタスクdo_applyからエラーを「返します」 。

あとは、これらのピースをプロジェクトにまとめるだけです。これはかなり簡単なはずです。

于 2013-09-07T12:51:38.220 に答える
0

データが保存されているかどうかをテストし、データが保存されているかどうかを確認するフラグを設定できます。次に、フラグが yes に設定されている場合のような if ステートメントを配置し、for ループを実行します。すべてのデータが保存されていることを確認するために、すべてのデータに対してそのようなことを行うことができます。幸運を!!お役に立てれば!!

于 2013-09-07T01:58:07.740 に答える