【问题标题】:Loop with delay or completion in objective c在目标 c 中延迟或完成循环
【发布时间】:2013-09-07 01:51:41
【问题描述】:

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

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

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

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

【问题讨论】:

  • 存储的数据在哪里?它在目录、核心数据等中吗?您期望有多少数据点? 10 还是 10,000?
  • @jb_OH 源数据来自核心数据,保存为PDF数据文件。数据是页面和页面的视图。每个页面可以有 1 - 无限次查看。每个视图也可能有数据,例如图像。

标签: ios loops completionhandler


【解决方案1】:

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

首先定义一个通用的完成块类型。注意,参数 result 可以是任何东西。如果是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 调用提供的完成块 completion(如果不是 nil)传递整个操作的结果,如果成功则为 @"OK" , 和 NSError 以防失败。

现在,更有趣的部分是:如何在一个循环中进行,其中许多 _task_s 将一个接一个地依次执行:

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

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

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

这是一个调用task N次的函数,传递给它的参数indexlowerBound(包括)到upperBound(不包括),其中 N 等于 upperBound - lowerBoundindex 以 下界。

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

这里是实现:

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] 顺序调用 task 参数 索引":

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 将调用自身,参数索引加一。这可能看起来像“递归” - 但事实并非如此。 do_apply 在调用自身时已经返回。

如果 task 返回并出错,do_apply 停止,在其完成处理程序中“返回”来自 task 的错误(最终由调用站点提供) .

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多