2017-02-01 5 views
1

오류 메시지를 보내는 기능 (sendError)이 있습니다. 그리고 5 초 후에 다음과 같이 제거됩니다 :디스패치 명령 덮어 쓰기

-(void)sendError:(NSString*)message{ 
    _errorMessage.stringValue = message; 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     _errorMessage.stringValue = @""; 
    }); 
} 

문제는 버튼의 경우 한 번 실행하고 있다는 것입니다 다시 삼초이 메시지가 나중에 오히려 5 2 초 이상 제거됩니다 실행되고 이후 두 번째.

이전 디스패치를 ​​취소하고 새 디스패치를 ​​쓰려면 어떻게해야합니까 (덮어 쓰기).

답변

4

이렇게하는 데는 몇 가지 방법이 있습니다. 먼저 GCD 사용을 중단하고 이전 메커니즘 인 -performSelector:withObject:afterDelay:으로 돌아갈 수 있습니다. 이점은 아직 계류중인 수행 요청을 취소하는 방법 +cancelPreviousPerformRequestsWithTarget:selector:object:이 있다는 것입니다.

-(void)sendError:(NSString*)message{ 
    _errorMessage.stringValue = message; 
    [NSObject cancelPreviousPerformRequestsWithTarget:_errorMessage selector:@selector(setStringValue:) object:@""]; 
    [_errorMessage performSelector:@selector(setStringValue:) withObject:@"" afterDelay:5]; 
} 

GCD를 계속 사용하려면 직접 취소를 추적해야합니다. 한 가지 방법은 "세대"수를 유지하는 것입니다. 따라서 _errorGeneration이라는 인스턴스 변수 NSUInteger이 있다고 가정합니다.

-(void)sendError:(NSString*)message{ 
    _errorMessage.stringValue = message; 
    _errorGeneration++; 
    NSUInteger capturedGeneration = _errorGeneration; 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     if (_errorGeneration == capturedGeneration) 
      _errorMessage.stringValue = @""; 
    }); 
} 

기본적으로 전달할 수 없기 때문에 전달 작업을 취소하지 않지만 더 이상 사용하지 않으면 아무 작업도 수행하지 않습니다.

+0

기술적으로 *이 솔루션에는 경쟁 조건이 있습니다. – bbum

+1

@bbum : 텍스트 필드라고 가정하는 'stringValue'를 수정하고 있기 때문에 메인 스레드에서 모든 것이 발생한다고 가정합니다. 이 경우 경주는 어디 있습니까? –

+0

그 가정이 성립한다면, 확실히! – bbum