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 将依次执行,一个接一个:

我们定义了两个辅助方法 - 或函数:

我们最终需要的是一个带有这个签名的函数:

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

这是调用任务N 次的函数,将参数index传递给从lowerBound(包括)到upperBound(不包括)的范围,其中N等于upperBound - lowerBound并且indexlowerBound开头。

它是一个异步函数,因此将完成块作为最后一个参数。我重复自己吗?好吧,你应该认出这个模式!;)

这是实现:

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

而另一个助手 - 最终执行某种“ for_each index in range[upperBound, lowerBound] 顺序调用带有参数index的任务”:

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”调用完成处理程序。否则,它使用参数索引调用任务并提供一个完成处理程序,该处理程序在任务完成时被调用,它本身传递任务的结果。如果成功,将调用自身,参数索引加一。这可能看起来像“递归” - 但事实并非如此。已经返回,当它调用自己时。do_applydo_apply

如果任务返回并且错误,则停止,从其完成处理程序中的任务do_apply“返回”错误(最终由调用站点提供)。

现在,您只需将这些部分放在您的项目中 - 这应该相当容易。

于 2013-09-07T12:51:38.220 回答
0

您可以测试以查看数据是否已保存并设置标志以查看数据是否已保存。然后放置一个 if 语句,例如如果标志设置为 yes,然后运行 ​​for 循环。您可以对所有数据执行类似操作,以确保存储所有数据。祝你好运!!希望这可以帮助!!

于 2013-09-07T01:58:07.740 回答