2017-09-19 3 views
1

라이브러리에서 NSProgress 지원을 구현 중이며 모든 것이 제대로 작동하는지 테스트하기 위해 일부 단위 테스트를 작성했습니다. 이상적으로 나는 일부 추가 메타 데이터 (userInfo 키는 NSProgress 자체에서 사용하지 않지만 내 API 사용자는 사용할 수 있음)를 전달할 수 있기를 원하지만 현재는 localizedDescriptionlocalizedAdditionalDescription을 문서와 같이 작동 시키려고합니다. 그들은해야한다고 말한다. 테스트 할 방법은 아카이브에서 파일을 추출하므로 kindNSProgressKindFile으로 설정하고 파일 작업과 관련된 다양한 키 (예 : NSProgressFileCompletedCountKey)를 설정합니다.자식 NSProgress 인스턴스의 NSProgress userInfo 변경 방법

처리 "테스트 파일 B.jpg"

처리 "a.txt이 테스트 파일"내가 KVO와 localizedDescription에 변화를 관찰 할 때

는 나는이 같은 업데이트를 볼 것으로 기대

처리 "테스트 파일 C.m4a"나는 중단 점 및 po 상기 정지

작업자의 localizedDescriptionNSProgress 인스턴스 (childProgress)가 실제로 표시됩니다. 내 테스트를 실행할 때, 그들은 모두 볼 다음이가 userInfo 키 중 하나가 표시되지 않는 것 의미이며, 내가 설정 :

0 %

0 % 완료

53 % 완료

를 완료

% 100 %가

0,123,516

완료

100

완료

userInfo 키에 설정된 NSProgress 인스턴스의 키가 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을 증가시,이 사용자 정보는 디버거의 모습입니다.

> po childProgress.userInfo 

{ 
    NSProgressFileCompletedCountKey = 2, 
    NSProgressFileTotalCountKey = 3, 
    NSProgressFileURLKey = "file:///...Test%20File%20B.jpg"; // chunk elided from URL 
} 

각 KVO 알림이 돌아 오면

, 이것은 notificationProgress.userInfo 보이는 방법은 다음과 같습니다 :

> po notificationProgress.userInfo 

{ 
} 
+0

컨텍스트에 대해 더 많은 코드를 표시 할 수 있습니까? setUserInfoObject를 호출 한 직후 콘솔에 po myCustomObject, po MyCustomKey 및 po [childProgress userInfo]가 표시됩니다. – clarus

+0

@clarus'po' 출력을 추가했습니다. 문맥에 필요한 다른 코드는 무엇입니까? 'NSProgress'와 관련이있는 것은별로 없습니다. 'fractionCompleted'가 정확하게보고되고 있습니다. – Dov

+0

observeValueForKeyPath : ofObject의 코드는 무엇입니까? : change : context : look like? 그리고 위에서 parentProgress를 사용하는 곳은 원래 childProgress 객체 참조와 동일합니까? – clarus

답변

2

좋아, 내가 더 커피를 다시 코드를 볼 수있는 기회가 내가 설정 한 필드는 모두 표시됩니다 내 시스템에서 그리고 내 손에 더 많은 시간을. 나는 실제로 그것이 작동하는 것을보고있다. , 당신은 내가 추가 한 키 - 값을 볼 수 있습니다

po progress.userInfo { 
NSProgressEstimatedTimeRemainingKey = 10; 
TestKey = Test; 
} 

po progress.localizedAdditionalDescription 
0 of 1 — About 10 seconds remaining 

:

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

그리고 observeValueForKeyPath에, 나는 이러한 개체를 인쇄 : 당신의 testProgressReporting_ExtractFiles_AdditionalDescription 방법에

, 나는이에 코드를 변경 해당 항목을 기반으로 localizedAdditionalDescription이 생성되었습니다 (남은 시간을 확인하십시오). 그래서이 모든 것이 올바르게 작동하는 것처럼 보입니다.

NSProgress 속성과 userInfo dict의 키 - 값에 대한 영향에 대해 혼란이있을 것이라고 생각합니다. 속성을 설정해도 userInfo dict에 키 - 값이 추가되지 않으며 키 - 값을 설정해도 속성이 설정되지 않습니다. 예를 들어 진행률 종류를 설정해도 NSProgressFileOperationKindKey가 userInfo dict에 추가되지는 않습니다. userInfo dict의 값은 localizedAdditionalDescription을 만들 때만 사용되는 속성보다 우선합니다.

내가 추가 한 맞춤 키 - 값을 볼 수도 있습니다. 그래서이 모든 것이 제대로 작동하는 것처럼 보입니다. 아직도 눈에 띄는 뭔가를 가르쳐 주시겠습니까?

+0

그건 재미 있어요. 나는 부모의 진보를 깊이 생각하지 않을 것이라고 생각했다. 나는 그것이 내가 의도하는 방식으로 일하기로되어 있다고 생각한다. 계층 구조는 NSProgress가 작동하는 방식에 깊이 뿌리 내리고 있습니다. 그것을 확인해 주셔서 감사합니다. – Dov

+0

더 자세히 보았을 때 텍스트가 업데이트되었으므로 아무 것도 추가하지 않았으므로 앞에서 내 의견이 삭제되었습니다. – clarus

+0

고맙습니다. 감사합니다. 그 변화를 만드는 것이 어디가 짧은가 생각합니다.'URKArchive' 클래스의 작업자 인'NSProgress '의 업데이트가 여전히 전파되지 않는다는 것입니다. 'URKArchive'의'progress' 객체를'po' 할 때, 항상 설정된 모든 키를 보여주었습니다. 말이 돼? – Dov

2

나는 @ clarus의 대답에 대해 의견을 말하고 싶었지만, 그래서 주석에서 읽을 수있는 형식을 허용하지 않을 것입니다. TL, DR - 필자의 생각은 언제나 나의 이해이며, 내가 몇 년 전에 NSProgress으로 일하기 시작했을 때 나를 조금 깨워 주었다.

이와 같은 이유로 구현상의 힌트를 Swift Foundation 코드에서 확인하고 싶습니다. 물건을 아직 완성하지 못했다면 100 % 권위가 아닐지 모르지만 나는 일반적인 생각을하는 것을 좋아합니다.

setUserInfoObject(: forKey:)의 구현을 보면 구현이 단순히 부모까지 전파하지 않고 사용자 정보를 설정한다는 것을 알 수 있습니다.

반대로 어린이의 분수에 영향을주는 업데이트는 explicitly call back을 (개인) _parent 속성으로 완료하여 자식 변경에 대한 응답으로 상태가 업데이트되어야 함을 나타냅니다.

개인 _updateChild(: from: to: portion:)은 완료된 부분 만 업데이트하고 사용자 정보 사전과 관련된 부분은 업데이트하지 않는 것으로 보입니다.

+0

감사합니다. 도움이됩니다. – Dov