在目标c中延迟或完成循环

时间:2013-09-07 01:51:41

标签: ios loops completionhandler

我有一个应用程序,其中我需要循环并加载存储的数据,以生成保存到PDF文件,页面的信息。我创建了一个循环,但它运行得太快,可以这么说。保存的页面加载速度不够快,因此生成的数据不完整。我想我需要创建一个带有延迟或完成处理程序的for循环。类似的东西:

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

甚至不确定如何编写伪代码,但基本上我只想在完成加载数据任务的完成处理程序之后跳转到下一次迭代。

注意:源数据来自核心数据,保存为PDF文件。数据是页面的页面和视图。每个页面可以有1个或无限制的视图。每个视图也可能包含数据,如图像。目前发生的事情是写入的页数是正确的,但是呈现给PDF的页面视图是相同的,因为它们都读取相同的数据,因为在写入PDF之前未加载页面。

2 个答案:

答案 0 :(得分:1)

您可以按如下方式解决问题:

首先定义通用完成块类型。注意,param 结果可以是任何东西。如果它是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:是异步的,因此,它将完成块作为最后一个参数。完成块的参数 result 是异步任务的结果,即“页面数组” - 如果失败则为NSError对象。

在此完成块中,您可以将结果(页面)保护到磁盘,并调用writeDataToFile:。 (我们假设这不会失败)。如果全部完成, task 将调用提供的完成块完成(如果不是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 index 以< EM>下界

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

以下是实施:

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

另一个帮助器 - 它最终在范围[upperBound,lowerBound] 顺序执行某种“ for_each索引使用参数调用任务索引 “:

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

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

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

答案 1 :(得分:0)

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