7

假设我有一些NSProgress对象层次结构。为简单起见,假设有 2 个孩子的根进度。如果进度已经开始,我可以向层次结构添加另一个子进度并期望发生正确的事情吗?例如,假设我从 2 个孩子开始,所以totalUnitCount根的 是2pendingUnitCount2。一旦第一个孩子完成,根进度fractionCompleted将是0.5. 如果我然后添加另一个子进度,根进度会按我的fractionCompleted意愿更新,但根进度保持在,就像. 我可以手动更新,但这会导致 root关闭。此外,似乎没有办法在不调用的情况下更新. 曾是~0.33totalUnitCount2pendingUnitCounttotalUnitCountfractionCompletedpendingUnitCountbecomeCurrentWithPendingUnitCount:NSProgress不是为这种用途而设计的,还是有“正确”的方法来做到这一点?

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

这是我编写的用于动态扩展NSProgress层次结构的单元测试。下面测试中的所有断言都通过了,但是如果您检查根totalUnitCount,它始终保持为 2,并且似乎无法判断根进度还有多少项目需要完成。根进度是 UI 将观察到的进度,因此层次结构中更深层次的更改向上传播很重要,包括totalUnitCount等。

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

    NSProgress *child1 = [NSProgress progressWithTotalUnitCount:1];
    NSProgress *child2 = [NSProgress progressWithTotalUnitCount:1];
    XCTAssertEqual(root.totalUnitCount, 2);
    XCTAssertEqual(root.completedUnitCount, 0);

    child1.completedUnitCount++;
    XCTAssertEqual(ceil(root.fractionCompleted * 100), 50);

    NSProgress *child3 = [NSProgress progressWithTotalUnitCount:1];
    NSProgress *child4 = [NSProgress progressWithTotalUnitCount:1];
    XCTAssertEqual(ceil(root.fractionCompleted * 100), 25);

    child2.completedUnitCount++;
    XCTAssertEqual(ceil(root.fractionCompleted * 100), 50);

    child3.completedUnitCount++;
    XCTAssertEqual(ceil(root.fractionCompleted * 100), 75);

    child4.completedUnitCount++;
    XCTAssertEqual(ceil(root.fractionCompleted * 100), 100);

    __unused NSProgress *child5 = [NSProgress progressWithTotalUnitCount:1];
    XCTAssertEqual(ceil(root.fractionCompleted * 100), 80);
}
4

2 回答 2

5

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

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

原因是我们无法更新父级的已完成单元计数,而子级“组”中的任何成员(那些在当前进度时作为子级进度附加到它的成员)未完成。一旦该组的所有成员都完成了,我们将该组与父组分离并增加父组的已完成单元计数。这保留了对已完成工作的正确核算。本地化描述方法说明了这一点,这就是为什么它给出的结果与 completedUnitCount 属性不同的原因。

如果您想更密切地跟踪这些孩子的完成情况,那么您可以让父母更频繁地成为最新的,并且单元数更少。然后,当孩子完成时,父母将更频繁地更新其完成的单元计数。

于 2014-04-23T22:29:57.967 回答
1

好吧,我想我知道我做错了什么。在添加新子节点之前,根必须完成正在进行的工作并调用 resignCurrent。然后根可以更新totalUnitCount,再次成为当前新的未决单元计数,孩子们可以工作。似乎 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
}
于 2014-04-21T21:11:35.037 回答