假设我有NSProgress
个对象的层次结构。为简单起见,请说2个孩子的根进度。如果已经开始进度,我可以在层次结构中添加另一个子进程并期望正确的事情发生吗?例如,假设我从2个孩子开始,因此根的totalUnitCount
为2
,pendingUnitCount
为2
。第一个孩子完成后,根进度“fractionCompleted
将为0.5
。如果我然后添加另一个子进度,根进度“fractionCompleted
会根据我的意愿更新到~0.33
,但根totalUnitCount
仍为2
,{{1}也是如此}}。我可以手动更新pendingUnitCount
,但会关闭根totalUnitCount
。此外,似乎无法在不调用fractionCompleted
的情况下更新pendingUnitCount
。 becomeCurrentWithPendingUnitCount:
是不是为这种用途设计的,还是有“正确”的方式来做到这一点?
我的用例是我有一个可以将文件上传到远程服务器的应用程序。用户可以选择一些文件并点击按钮开始上传它们。在他们上传时,用户可以看到上传作业的整体进度。现在,如果用户想要在上传已经进行时选择要上传的更多照片,我想更新进度以反映新的总数。例如,他目前正在上传2个文件,1个已经完成,当他们上传时,他还增加了2个上传文件。进展应该自我调整。现在总单位数应为4,并且还有3个项目要上传。对我来说这似乎是一个常见的用例。
这是我编写的用于动态扩展NSProgress
层次结构的单元测试。下面测试中的所有断言都会通过,但是如果检查根NSProgress
,它始终保持为2,并且似乎无法确定从根进度中完成剩余的项目数。根进度是UI将观察到的进度,因此层次结构中更深层次的更改会传播,包括totalUnitCount
等,这一点非常重要。
totalUnitCount
答案 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
}