6

我正在使用NSProgress在我的 iOS 应用程序中传达文件下载的进度。这是一个非常通用的类,我有点害怕它的内在力量,尤其是两个完成处理属性。有一个用于处理取消,一个用于暂停(但没有一个用于完成,这可能是一个打击......)

这些处理程序的用途是什么?执行下载的代码可以将逻辑放入其中以处理用户发起的取消和暂停。但是,没有什么可以阻止客户端使用 UI 代码覆盖处理程序。

那么,它是为 UI 设计的吗?我不确定这是一个有用的模式,因为无论如何 UI 都会发起取消或暂停。此外,如果您使用进度对象同时显示多个 UI 元素的进度(在 MacOS 中使用的方式),则不同的 UI 元素可能都需要自己的完成处理程序。

使用处理程序将用户操作传回下载控制器似乎是最有用的模式,但我本来希望处理程序在初始化时设置,然后保持只读状态。

我在这里想念什么?

(PS 现在我根本不打算使用这些处理程序并依赖 KVO。但是,我有一种很痒的感觉,我错过了课程背后的一些基本思想)

4

2 回答 2

1

我相信您缺少的关键是NSProgress该类旨在用作进度对象树。此外,这棵树是使用子进度对象隐式创建的,不需要知道它们附加到父级,这就是它真正强大的地方。

我发现 OS X Foundation Release Notes 比类参考更有帮助NSProgress

https://developer.apple.com/library/Mac/releasenotes/Foundation/RN-Foundation/index.html

处理程序似乎可用于 UI 控制器逻辑和数据控制器逻辑的原因是,当您构建父子层次结构时,您有两组可用于两者的处理程序。父处理程序将设置在 UI 控制器级别(进度的“消费者”),子处理程序将由数据控制器(“提供者”)设置。

由于可以使用becomeCurrentWithPendingUnitCount:子进程对象隐式创建关系,因此将与父进程对象隔离,这将减轻您对客户端用他们自己的覆盖任何数据级处理程序的担忧。

在进度对象上调用pausecancel将沿着树传播该调用,并在途中调用任何处理程序。

一个例子:

// UI controller level, probably a UIViewController subclass.
- (void)handleDoSomethingButtonTapped:(UIButton *)sender
{
    self.progressThatWeObserve =
        [NSProgress progressWithTotalUnitCount:100]; // 100 is arbitrary
    self.progressThatWeObserve.pausingHandler = ^{
        // Update UI, reflect paused state ...
    };

    [self.progressThatWeObserve becomeCurrentWithPendingUnitCount:100];
    [self.dataController doSomethingInBackgroundWithCompletionHandler:^{
        // Update UI, remove from view ...
    }];
    [self.progressThatWeObserve resignCurrent];
}

// Data controller level, a SomethingManager class maybe.
- (void)doSomethingInBackgroundWithCompletionHandler:(void (^)(void)completionHandler
{
    self.progressThatWeManipulate =
        [NSProgress progressWithTotalUnitCount:289234]; // e.g. bytes to upload
    self.progressThatWeManipulate.pausingHandler = ^{
        // Actually suspend the network operation ...
    };

    dispath_async(self.workerQueue, ^{
        // Periodically update progress
    });
}

请注意,我实际上并没有做过任何这些,这都是阅读文档的理论。

于 2014-02-21T01:32:11.743 回答
0

您可以将这些块用于您想要的任何东西。具体来说,如果你想对 UI 做一些事情,你应该确保在主线程上做,如文档的“特殊注意事项”部分所述,“可以在任何队列上调用取消处理程序。如果你必须这样做在特定队列上工作,您应该从取消处理程序块内分派到该队列。” 因此,对于 UI,您将使用:

dispatch_async(dispatch_get_main_queue(), ^{
    // Do work on UI
});

完成处理程序模式通常用于处理“总是”在后台完成的任务;I/O 任务,例如从服务器下载文件。在这种情况下,虽然定义一个用于暂停和取消的处理程序也很有用,因为您的应用程序中可能有许多事件调用 NSProgress 实例上的 pause: 或 cancel: 方法。

于 2013-10-07T04:24:07.407 回答