objective-c - 覆盖调度命令

标签 objective-c macos cocoa event-dispatch-thread

我有一个发送错误消息的函数 (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 = @"";
    });
}

问题是,如果按钮运行一次,然后 3 秒后再次运行,则第二次运行该消息将在 2 秒后删除,而不是 5 秒。

如何取消之前的调度并编写新的调度(覆盖)。

最佳答案

有几种方法可以做到这一点。首先,您可以停止使用 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,那么您需要自行跟踪取消情况。一种方法是保留“一代”计数。因此,假设存在一个名为 _errorGenerationNSUInteger 实例变量。

-(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 = @"";
    });
}

基本上,您不会取消分派(dispatch)的任务(因为您不能),但如果它已过时,您可以让它不执行任何操作。

关于objective-c - 覆盖调度命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41990860/

相关文章:

iphone - 使用 MKNetworkKit 下载文件的总大小

objective-c - CABasicAnimation 不起作用

macos - 为符号链接(symbolic link)设置图标

macos - vagrant homestead - 公共(public)网络无法在 osx 上运行

c - Cocoa app 和 C 端 app 之间的进程间通信

ios - 类方法+setLoggingEnabled : not found

objective-c - 为什么 Objective-C 方法名称的最后一部分必须带一个参数(当有多个部分时)?

swift - 拖放字符串/图像 NSTableView Swift

objective-c - NSString:isEqual 与 isEqualToString

ios - StoreKit 购买失败 - com.apple.accessibility.gax.backboard