假设我有一些NSProgress对象的层次结构。为了简单起见,假设根进程为2个子进程。如果进度已经开始,我是否可以将另一个子进度添加到层次结构中,并期望正确的事情发生?例如,假设我从2个子目录开始,那么根目录的totalUnitCount是2,pendingUnitCount是2。一旦第一个子进程完成,根进程的fractionCompleted将为0.5。如果我随后添加另一个子进程,根进程的fractionCompleted确实会按照我的意愿更新为~0.33,但是根进程的totalUnitCount仍然是2,pendingUnitCount也是如此。我可以手动更新totalUnitCount,但这会关闭根目录的fractionCompleted。此外,在不调用becomeCurrentWithPendingUnitCount:的情况下,似乎无法更新pendingUnitCount。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);
}发布于 2014-04-24 06:29:58
我向苹果提交了一个bug,他们的回应是:
工程部门已根据以下信息确定此问题的行为符合预期:
原因是我们不能在子代“组”中的任何成员都未完成时更新父代的已完成单元计数(子代进展时附加到子代的成员,而当前进度是未完成的)。一旦组的所有成员都完成了,我们就将该组从父组中分离出来,并递增父组的已完成单元计数。这保留了对已完成工作的正确计算。本地化的description方法说明了这一点,这就是为什么它会给出与completedUnitCount属性不同的结果。
如果您希望更密切地跟踪这些子进程的完成情况,则可以使用较小的单元计数使父进程更频繁地成为当前进程。然后,当子进程完成时,父进程将更频繁地更新其已完成的单元计数。
发布于 2014-04-22 05:11:35
好吧,我想我知道我做错了什么。在添加新的子级之前,根必须完成正在进行的工作并调用resignCurrent。然后,根可以使用新的挂起单元计数再次更新totalUnitCount、becomeCurrent,并且子节点可以执行工作。似乎currentProgress的completedUnitCount只有在退出current之后才会更新。这就是为什么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
}https://stackoverflow.com/questions/23202315
复制相似问题