Swift 如何在特定时间戳后终止完成处理程序

Swift 如何在特定时间戳后终止完成处理程序,swift,background-process,completionhandler,Swift,Background Process,Completionhandler,我已经在按钮操作中编写了完成处理程序,如下代码所示 func backgroundTask(arg: Bool, completion: (Bool) -> ()) { completion(arg) } 在我的按钮点击 backgroundTask(arg: true, completion: { (success) -> Void in if success { print("true") } else { pr

我已经在按钮操作中编写了完成处理程序,如下代码所示

func backgroundTask(arg: Bool, completion: (Bool) -> ()) {

    completion(arg)
}
在我的按钮点击

backgroundTask(arg: true, completion: { (success) -> Void in
    if success { 
          print("true")
    } else {
         print("false")
    }
})
当用户多次按下按钮时,完成处理程序返回的时间就相当长

需要多次返回完成处理程序


我需要设置一个时间戳,之后完成处理程序不需要返回。

您不能简单地取消关闭。您可以改为创建一个包含函数调用的DispatchWorkItem,然后取消该工作项。与简单调用backgroundTask不同,您应该在用户每次按下按钮时创建DispatchWorkItem,在项目上调用perform,如果截止日期已过,则调用cancel

独立操场示例:

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

func backgroundTask(arg: Bool, completion: (Bool) -> ()) {
    completion(arg)
}

backgroundTask(arg: true, completion: { (success) -> Void in
    if success {
        print("true")
    } else {
        print("false")
    }
})

let workItem = DispatchWorkItem(block: { backgroundTask(arg: true, completion: {
    (success) -> Void in
    if success {
        print("true")
        DispatchQueue.main.asyncAfter(deadline: .now()+2, execute: {
            print("Delayed success") //As long as the deadline is smaller than the deadline of `workItem.cancel()`, this will be printed
        })
    } else {
        print("false")
    }
})})

workItem.perform()
DispatchQueue.main.asyncAfter(deadline: .now()+3, execute: {
    workItem.cancel()
    PlaygroundPage.current.finishExecution()
})

您不能简单地取消关闭。您可以改为创建一个包含函数调用的DispatchWorkItem,然后取消该工作项。与简单调用backgroundTask不同,您应该在用户每次按下按钮时创建DispatchWorkItem,在项目上调用perform,如果截止日期已过,则调用cancel

独立操场示例:

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

func backgroundTask(arg: Bool, completion: (Bool) -> ()) {
    completion(arg)
}

backgroundTask(arg: true, completion: { (success) -> Void in
    if success {
        print("true")
    } else {
        print("false")
    }
})

let workItem = DispatchWorkItem(block: { backgroundTask(arg: true, completion: {
    (success) -> Void in
    if success {
        print("true")
        DispatchQueue.main.asyncAfter(deadline: .now()+2, execute: {
            print("Delayed success") //As long as the deadline is smaller than the deadline of `workItem.cancel()`, this will be printed
        })
    } else {
        print("false")
    }
})})

workItem.perform()
DispatchQueue.main.asyncAfter(deadline: .now()+3, execute: {
    workItem.cancel()
    PlaygroundPage.current.finishExecution()
})

如果我理解正确,看看这是否有效:

import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

let completionCancelDeadline: TimeInterval = 2.5

class Worker {
    init() {}

    private var completion: ((Bool) -> ())?

    func backgroundTask(arg: Bool, completion: ((Bool) -> ())?) {
        self.completion = completion

        DispatchQueue.main.asyncAfter(deadline: .now() + completionCancelDeadline) {
            self.completion = nil
        }

        worker(arg: arg)
    }

    private func worker(arg: Bool) {
        let randomTaskDuration = TimeInterval(arc4random_uniform(5))

        // randomTaskDuration is to simulate how long it's going to take the background task to complete
        // and if it completes later than the completionCancelDeadline then the completion will be nil
        DispatchQueue.main.asyncAfter(deadline: .now() + randomTaskDuration) {
            print("Time the background task took: \(randomTaskDuration) second(s)")
            print("Should the completion exist: \(randomTaskDuration < completionCancelDeadline)")
            self.completion?(arg)
            print("") // Adding a new line intentionally to separate each call
        }
    }
}

class ViewController: UIViewController {
    func buttonTap() {
        let worker = Worker()
        worker.backgroundTask(arg: true) { success in
            print("Completion called")
        }
    }
}

let vc = ViewController()
vc.buttonTap()
vc.buttonTap()
vc.buttonTap()
vc.buttonTap()

如果我理解正确,看看这是否有效:

import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

let completionCancelDeadline: TimeInterval = 2.5

class Worker {
    init() {}

    private var completion: ((Bool) -> ())?

    func backgroundTask(arg: Bool, completion: ((Bool) -> ())?) {
        self.completion = completion

        DispatchQueue.main.asyncAfter(deadline: .now() + completionCancelDeadline) {
            self.completion = nil
        }

        worker(arg: arg)
    }

    private func worker(arg: Bool) {
        let randomTaskDuration = TimeInterval(arc4random_uniform(5))

        // randomTaskDuration is to simulate how long it's going to take the background task to complete
        // and if it completes later than the completionCancelDeadline then the completion will be nil
        DispatchQueue.main.asyncAfter(deadline: .now() + randomTaskDuration) {
            print("Time the background task took: \(randomTaskDuration) second(s)")
            print("Should the completion exist: \(randomTaskDuration < completionCancelDeadline)")
            self.completion?(arg)
            print("") // Adding a new line intentionally to separate each call
        }
    }
}

class ViewController: UIViewController {
    func buttonTap() {
        let worker = Worker()
        worker.backgroundTask(arg: true) { success in
            print("Completion called")
        }
    }
}

let vc = ViewController()
vc.buttonTap()
vc.buttonTap()
vc.buttonTap()
vc.buttonTap()

我们需要知道你是如何执行后台任务的。如果我正确理解了你的问题,你可以通过将其设置为可选来杀死一个完成处理程序。。。完成:Bool->?在合适的时候把它设为零。但我不确定您的具体情况以及它如何适合您的应用程序。我们需要知道您如何执行后台任务。如果我正确理解您的问题,您可以通过将其设置为可选来杀死完成处理程序。。。完成:Bool->?在合适的时候把它设为零。但我不确定你的具体情况以及它如何适合你的应用程序。