代码之家  ›  专栏  ›  技术社区  ›  Dov

如何使用/测试子Nprogress实例的Nprogress userInfo更改

  •  1
  • Dov  · 技术社区  · 8 年前

    我正在实施 NSProgress 我写了一些单元测试来测试一切是否正常工作。理想情况下,我希望能够传递一些额外的元数据( userInfo 它本身,但对于我的API的用户来说),现在我只是想 localizedDescription localizedAdditionalDescription kind NSProgressKindFile 并设置与文件操作相关的各种键(例如。 NSProgressFileCompletedCountKey ).

    本地化描述 有了KVO,我将看到如下更新:

    处理测试文件A.txt

    处理测试文件C.m4a

    当我在断点处停止时 po 本地化描述 关于工人 childProgress 我设置的键:

    0%已完成

    0%已完成

    完成53%

    100%完成

    看起来像是 用户信息 我给孩子放的钥匙 实例没有传递给其父对象,即使 fractionCompleted 做我做错什么了吗?

    我在下面给出了一些抽象代码片段,但您也可以下载带有这些更改的提交 from 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;
        }
    }
    

    childProgress.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
    
    {
    }
    
    2 回复  |  直到 5 年前
        1
  •  4
  •   Jablair    8 年前

    我想对@clarus的回答发表评论,但我不想在评论中使用可读的格式。TL;博士-他们的想法一直是我的理解,当我开始与他们合作时,这件事对我来说有点小 NSProgress 几年前。

    Swift Foundation 实现提示代码。如果事情还没有完成,这可能不是百分之百的权威,但我喜欢看到一般的想法。

    如果你看一下 setUserInfoObject(: forKey:) 您可以看到,该实现只需设置用户信息dict,而不向父级传播任何内容。

    相反,影响孩子分数的更新已完成 explicitly call back _parent 属性来指示其状态应更新以响应子更改。

    _updateChild(: from: to: portion:) 似乎只关心更新已完成的分数,而与用户信息字典无关。

        2
  •  3
  •   clarus    8 年前

    在testProgressReporting\u ExtractFiles\u AdditionalDescription方法中,我将代码更改为:

    NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1];
    [extractFilesProgress setUserInfoObject:@10 forKey:NSProgressEstimatedTimeRemainingKey];
    [extractFilesProgress setUserInfoObject:@"Test" forKey:@"TestKey"];
    

    然后在observeValueForKeyPath中,我打印了这些对象:

    po progress.userInfo {
    NSProgressEstimatedTimeRemainingKey = 10;
    TestKey = Test;
    }
    
    po progress.localizedAdditionalDescription
    0 of 1 — About 10 seconds remaining
    

    您可以看到我添加的键值,localizedAdditionalDescription是基于这些条目创建的(请注意剩余的时间)。所以,这一切看起来都正常工作。

    我认为一个混淆点可能是Nprogress属性及其对userInfo dict中键值的影响。设置属性不会向userInfo dict添加键值,设置键值也不会设置属性。例如,设置进度类型不会将NSProgressFileOperationKindKey添加到userInfo dict。userInfo dict中的值(如果存在)更多地是对仅在创建localizedAdditionalDescription时使用的属性的重写。