进度开始后是否可以动态扩展NSProgress层次结构?

时间:2014-04-21 17:23:08

标签: ios nsprogress

假设我有NSProgress个对象的层次结构。为简单起见,请说2个孩子的根进度。如果已经开始进度,我可以在层次结构中添加另一个子进程并期望正确的事情发生吗?例如,假设我从2个孩子开始,因此根的totalUnitCount2pendingUnitCount2。第一个孩子完成后,根进度“fractionCompleted将为0.5。如果我然后添加另一个子进度,根进度“fractionCompleted会根据我的意愿更新到~0.33,但根totalUnitCount仍为2,{{1}也是如此}}。我可以手动更新pendingUnitCount,但会关闭根totalUnitCount。此外,似乎无法在不调用fractionCompleted的情况下更新pendingUnitCountbecomeCurrentWithPendingUnitCount:是不是为这种用途设计的,还是有“正确”的方式来做到这一点?

我的用例是我有一个可以将文件上传到远程服务器的应用程序。用户可以选择一些文件并点击按钮开始上传它们。在他们上传时,用户可以看到上传作业的整体进度。现在,如果用户想要在上传已经进行时选择要上传的更多照片,我想更新进度以反映新的总数。例如,他目前正在上传2个文件,1个已经完成,当他们上传时,他还增加了2个上传文件。进展应该自我调整。现在总单位数应为4,并且还有3个项目要上传。对我来说这似乎是一个常见的用例。

这是我编写的用于动态扩展NSProgress层次结构的单元测试。下面测试中的所有断言都会通过,但是如果检查根NSProgress,它始终保持为2,并且似乎无法确定从根进度中完成剩余的项目数。根进度是UI将观察到的进度,因此层次结构中更深层次的更改会传播,包括totalUnitCount等,这一点非常重要。

totalUnitCount

2 个答案:

答案 0 :(得分:4)

我向Apple提交了一个错误,这是他们的回复:

Engineering已根据以下信息确定此问题的行为符合预期:

原因是我们无法更新父母已完成的单位数,而“子组”中的任何成员(作为子进程的子进程,当进展是最新的)都未完成。完成组中的所有成员后,我们将该组与父组分离,并递增父组的已完成单元数。这保留了对已完成工作的正确记帐。本地化描述方法解释了这一点,这就是为什么它给出了与completedUnitCount属性不同的结果。

如果您想更密切地跟踪这些孩子的完成情况,那么您可以让父母更频繁地使用较小的单位数。然后,当孩子完成后,父母将更频繁地更新其完成的单元数。

答案 1 :(得分:1)

好吧,我想我知道我做错了什么。在添加新子项之前,root必须完成正在进行的工作并调用resignCurrent。然后root可以使用新的挂起单位计数再次更新totalUnitCount,becomeCurrent,并且子节点可以正常工作。似乎currentProgress的completedUnitCount直到它撤销当前才更新。这就是localizedAdditionalDescription错误的原因。不确定这是设计还是错误,但这意味着如果我要动态地将子节点添加到进度层次结构中,我就不能依赖根节点的completedUnitCount。

- (void)testDynamicNSProgress2
{
    NSProgress *root = [NSProgress progressWithTotalUnitCount:2];
    [root becomeCurrentWithPendingUnitCount:2];

    XCTAssertEqual(root.completedUnitCount, 0);
    NSLog(@"%@", root.localizedDescription);           // 0% completed
    NSLog(@"%@", root.localizedAdditionalDescription); // 0 of 2

    // Add two children
    NSProgress *child1 = [NSProgress progressWithTotalUnitCount:1];
    NSProgress *child2 = [NSProgress progressWithTotalUnitCount:1];

    // First child completes work    
    child1.completedUnitCount++;
    XCTAssertEqual(root.completedUnitCount, 0);
    NSLog(@"%@", root.localizedDescription);           // 50% complete
    NSLog(@"%@", root.localizedAdditionalDescription); // 1 of 2

    // Second child completes work
    child2.completedUnitCount++;
    [root resignCurrent];
    XCTAssertEqual(root.completedUnitCount, 2);
    NSLog(@"%@", root.localizedDescription);           // 100% complete
    NSLog(@"%@", root.localizedAdditionalDescription); // 2 of 2

    // Update totalUnitCount and become current again
    root.totalUnitCount = 3;
    [root becomeCurrentWithPendingUnitCount:1];
    XCTAssertEqual(root.completedUnitCount, 2);
    XCTAssertEqual(root.totalUnitCount, 3);
    NSLog(@"%@", root.localizedDescription);           // 66% completed
    NSLog(@"%@", root.localizedAdditionalDescription); // 1 of 3 (wrong! should be 2 of 3)

    // Last child completes
    NSProgress *child3 = [NSProgress progressWithTotalUnitCount:1];
    child3.completedUnitCount++;
    [root resignCurrent];
    XCTAssertEqual(root.completedUnitCount, 3);
    NSLog(@"%@", root.localizedDescription);           // 100% completed
    NSLog(@"%@", root.localizedAdditionalDescription); // 3 of 3
}