取消Swift中的定时事件?

max*_*hud 51 events swift

我想在一个事件的10秒内运行一段代码,但是我希望能够取消它,这样如果在那10秒之前发生了某些事情,代码将在10秒后不再运行.

我一直在使用它,但它不可取消:

static func delay(delay:Double, closure:()->()) {
  dispatch_after(
    dispatch_time(
      DISPATCH_TIME_NOW,
      Int64(delay * Double(NSEC_PER_SEC))
    ),
    dispatch_get_main_queue(), closure
  )
}
Run Code Online (Sandbox Code Playgroud)

我怎么能做到这一点?

Dav*_*son 222

Swift 3有DispatchWorkItem:

let task = DispatchWorkItem { print("do something") }

// execute task in 2 seconds
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: task)

// optional: cancel task
task.cancel()
Run Code Online (Sandbox Code Playgroud)

  • 请注意,task.cancel()将取消所有挂起的DispatchWorkItem事件,并阻止任何FUTURE DispatchWorkItem事件运行.如果您尝试创建类似于重复打开和关闭的重复轮询计时器,则每次要"重新启动"计时器时,如果已"取消"该任务,则需要创建一个新的DispatchWorkItem.本质上,task.cancel()使DispatchWorkItem"无效",不能再次使用它.我怀疑Apple内部为DispatchWorkItem设置了isCancelled标志,我没有看到"清除"该标志以供重用的方法.我认为这是一个"功能". (13认同)
  • 在Swift 3中这似乎是一种正确的方法.应该接受答案. (6认同)

Sau*_*hah 20

Swift 3.0的更新

设置执行选择器

perform(#selector(foo), with: nil, afterDelay: 2)
Run Code Online (Sandbox Code Playgroud)

foo方法将在2秒后调用

 func foo()
 {
         //do something
 }
Run Code Online (Sandbox Code Playgroud)

取消待处理的方法调用

 NSObject.cancelPreviousPerformRequests(withTarget: self)
Run Code Online (Sandbox Code Playgroud)

  • 优秀的答案! (2认同)

sas*_*sas 12

试试这个(Swift 2.x,请参阅下面的David对Swift 3的回答):

typealias dispatch_cancelable_closure = (cancel : Bool) -> ()

func delay(time:NSTimeInterval, closure:()->()) ->  dispatch_cancelable_closure? {

    func dispatch_later(clsr:()->()) {
        dispatch_after(
            dispatch_time(
                DISPATCH_TIME_NOW,
                Int64(time * Double(NSEC_PER_SEC))
            ),
            dispatch_get_main_queue(), clsr)
    }

    var closure:dispatch_block_t? = closure
    var cancelableClosure:dispatch_cancelable_closure?

    let delayedClosure:dispatch_cancelable_closure = { cancel in
        if let clsr = closure {
            if (cancel == false) {
                dispatch_async(dispatch_get_main_queue(), clsr);
            }
        }
        closure = nil
        cancelableClosure = nil
    }

    cancelableClosure = delayedClosure

    dispatch_later {
        if let delayedClosure = cancelableClosure {
            delayedClosure(cancel: false)
        }
    }

    return cancelableClosure;
}

func cancel_delay(closure:dispatch_cancelable_closure?) {
    if closure != nil {
        closure!(cancel: true)
    }
}

// usage
let retVal = delay(2.0) {
    println("Later")
}
delay(1.0) {
    cancel_delay(retVal)
}
Run Code Online (Sandbox Code Playgroud)

来自Waam的评论:dispatch_after - GCD in swift?


jma*_*tar 5

你需要这样做:

class WorkItem {

private var pendingRequestWorkItem: DispatchWorkItem?

func perform(after: TimeInterval, _ block: @escaping VoidBlock) {
    // Cancel the currently pending item
    pendingRequestWorkItem?.cancel()

    // Wrap our request in a work item
    let requestWorkItem = DispatchWorkItem(block: block)

    pendingRequestWorkItem = requestWorkItem

    DispatchQueue.main.asyncAfter(deadline: .now() + after, execute: 
    requestWorkItem)
}
}

// to use

lazy var workItem = WorkItem()

private func onMapIdle() {

    workItem.perform(after: 1.0) {

       self.handlePOIListingSearch()
    }
}
Run Code Online (Sandbox Code Playgroud)

参考

链接 swiftbysundell

链接 git