代码之家  ›  专栏  ›  技术社区  ›  Alfonso Tesauro

在MacOS应用程序中,我有一个后台线程,执行一行代码需要花费很多时间。如何取消该块?

  •  1
  • Alfonso Tesauro  · 技术社区  · 7 年前

    在我正在开发的CocoaObjective-C应用程序中,我有一个具有委托的InstableView,该委托实现了TableViewSelectionDidChange。在方法的委托实现中,我放置了一个使用gcd实现的后台串行队列,它处理在表中加载当前所选对象,以便在表右侧的详细nsview中显示该对象。我期望的行为是,如果后台线程没有完成,并且在左表中有一个新的选择,我想取消它并为新的选择启动一个新的线程。我用GCD找到了一个非常优雅的解决方案 here 使用:

    dispatch_block_cancel(work);
    

    问题是,正如链接中所说:

    “需要注意的一点是,调度块取消不是先发制人的。如果工作块处于长时间运行操作的中间,则调度块取消不会强制终止它。要做到这一点,我们必须定期用调度块测试取消。以下是一个例子:“

    for (...) {
        /* do some work */
        [NSThread sleepForTimeInterval:0.2];
    
        if (dispatch_block_testcancel(work) != 0) {
            /* exit gracefully */
            return;
        }
    }
    

    问题是,在我的应用程序中,在TableViewSelectionDidChange实现中执行的最长操作是在一行代码中,我无法重构代码来更改此操作,因为该语句正在调用我正在使用的外部dylib。在这种情况下,我无法检查该块是否被取消:

    if (dispatch_block_testcancel(work) != 0) {
            /* exit gracefully */
            return;
    }
    

    因为线程在冗长的单行操作中被阻塞。希望有人能提出某种策略,最好还是使用GCD?我知道nsOperation和nsOperationQueue,但是在学习使用它们之前,我想确定它们不会像gcd那样在一行语句中间取消操作。非常感谢你的帮助。

    1 回复  |  直到 7 年前
        1
  •  3
  •   Rob Napier    7 年前

    这是无法解决的。使用哪种工具并不重要(GCD与NSOperation)。无法强制停止正在进行的操作。它会使内存处于未知状态。解决方案是等待代码行完成,然后如果块被取消,则删除结果。如果代码行非常昂贵,以至于您确实需要终止它(而不只是忽略它的结果),那么您必须用检查取消标志的代码替换库。