我正在NSProgress
一个库中实现支持,并且我编写了一些单元测试来测试一切是否正常工作。虽然理想情况下我希望能够传递一些额外的元数据(userInfo
密钥本身不使用NSProgress
,但供我的 API 的用户使用),但现在我只是想像文档所说的那样获取localizedDescription
和localizedAdditionalDescription
工作。由于我正在测试的方法是从存档中提取文件,因此我设置了kind
toNSProgressKindFile
并设置了与文件操作相关的各种键(例如NSProgressFileCompletedCountKey
)。
我希望当我观察到localizedDescription
KVO 的变化时,我会看到这样的更新:
处理“测试文件 A.txt”</p>
处理“测试文件 B.jpg”</p>
处理“测试文件 C.m4a”</p>
当我停在断点和工作实例上(po
如下)时,这实际上就是我所看到的。但是当我的测试运行时,他们看到的只是以下内容,这意味着它没有看到我设置的任何键:localizedDescription
NSProgress
childProgress
userInfo
0% 完成
0% 完成
53% 完成
100% 完成
100% 完成
看起来userInfo
我在子NSProgress
实例上设置的键没有传递给它的父实例,即使这样fractionCompleted
做了。难道我做错了什么?
我在下面给出了一些抽象代码片段,但您也可以从 GitHub下载包含这些更改的提交。如果您想重现此行为,请运行-[ProgressReportingTests testProgressReporting_ExtractFiles_Description]
和-[ProgressReportingTests testProgressReporting_ExtractFiles_AdditionalDescription]
测试用例。
在我的测试用例类中:
static void *ProgressContext = &ProgressContext;
...
- (void)testProgressReporting {
NSProgress *parentProgress = [NSProgress progressWithTotalUnitCount:1];
[parentProgress becomeCurrentWithPendingUnitCount:1];
[parentProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(localizedDescription))
options:NSKeyValueObservingOptionInitial
context:ProgressContext];
MyAPIClass *apiObject = // initialize
[apiObject doLongRunningThing];
[parentProgress resignCurrent];
[parentProgress removeObserver:self
forKeyPath:NSStringFromSelector(@selector(localizedDescription))];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context
{
if (context == ProgressContext) {
// Should refer to parentProgress from above
NSProgress *notificationProgress = object;
[self.descriptionArray addObject:notificationProgress.localizedDescription];
}
}
然后,在我的测试课上:
- (void) doLongRunningThing {
...
NSProgress *childProgress = [NSProgress progressWithTotalUnitCount:/* bytes calculated above */];
progress.kind = NSProgressKindFile;
[childProgress setUserInfoObject:@0
forKey:NSProgressFileCompletedCountKey];
[childProgress setUserInfoObject:@(/*array count from above*/)
forKey:NSProgressFileTotalCountKey];
int counter = 0;
for /* Long-running loop */ {
[childProgress setUserInfoObject: // a file URL
forKey:NSProgressFileURLKey];
// Do stuff
[childProgress setUserInfoObject:@(++counter)
forKey:NSProgressFileCompletedCountKey];
childProgress.completedUnitCount += myIncrement;
}
}
在我 incrementchildProgress.completedUnitCount
时,这就是调试器中 userInfo 的样子。我设置的字段都表示:
> po childProgress.userInfo
{
NSProgressFileCompletedCountKey = 2,
NSProgressFileTotalCountKey = 3,
NSProgressFileURLKey = "file:///...Test%20File%20B.jpg"; // chunk elided from URL
}
当每个 KVO 通知返回时,如下所示notificationProgress.userInfo
:
> po notificationProgress.userInfo
{
}