Hunter
Hunter

Reputation: 1391

How to reset a Completion Handler in Swift

I have a function. It runs great but when I want to call it again it knows that that function has already been completed before so if I try to call it again it will automatically pass to completed. How do I reset the completion handler?

Code:

func Test(completionHandler: @escaping (_ finished: String?) -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
        completionHandler("finished") // tell the caller that this has completed
    }
}

I call it like this:

self.Test(completionHandler: { finished in
     print("We have completed function)")
})

If I were to call it again after about a minute. Instead of it waiting 10 seconds like its supposed. It will automatically printed line.

print("We have completed function)")

Things to know:

The code above is a test example me real code is this.

   func GoToPage(completionHandler: @escaping (_ finished: String?) -> Void) {
        self.webView.evaluateJavaScript("document.getElementById('results').getElementsByClassName('page')[0].getElementsByClassName('name')[0].innerText"){ (value, error) in
        if error != nil {
        } else {
        print(value)
        completionHandler("finished")
        }
        }
}

I call it like this:

     self.GoToPage(completionHandler: { finished in
     print("We have completed function)")
     })

Then I wait one 1-2 minutes and call it again like this the same way.

    DispatchQueue.main.asyncAfter(deadline: .now() + 130.0) {
     self.GoToPage(completionHandler: { finished in
     print("We have completed function")
     })
    }

An it prints me the line We have completed function right off the bat when called.

EXAMPLE:

This puts it all together

     self.GoToPage(completionHandler: { finished in
     print("We have completed function)")
     NextStep()
     })


     func NextStep(){
     DispatchQueue.main.asyncAfter(deadline: .now() + 130.0) {
     self.GoToPage(completionHandler: { finished in
     print("We have completed function")
     })
     }
     }


     func GoToPage(completionHandler: @escaping (_ finished: String?) -> Void) {
        self.webView.evaluateJavaScript("document.getElementById('results').getElementsByClassName('page')[0].getElementsByClassName('name')[0].innerText"){ (value, error) in
        if error != nil {
        } else {
        print(value)
        completionHandler("finished")
        }
        }
        }

Upvotes: 0

Views: 253

Answers (1)

Puneet Sharma
Puneet Sharma

Reputation: 9484

It is working as it is supposed to work.
DispatchQueue.main.asyncAfter is an async function, i.e. when you are calling the self.test, the function returns after asking main thread to asynchronously wait for 10 seconds, and then immediately you ask the function to do the same for second time.
If you want the function to wait for the first execution, one way to do this is to call the function for second time in its completion handler:

self.Test(completionHandler: { finished in
    print("We have completed function)")
    self.Test(completionHandler: { finished in
        print("We have completed function)")
    })
})

EDIT: code in playground. Prints second function after about 10 seconds.

class TestAsyncAfter {

    func nextStep(){
        DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
            self.goToPage(completionHandler: { finished in
                print("We have completed function")
            })
        }
    }

    func goToPage(completionHandler: @escaping (_ finished: String?) -> Void) {
        completionHandler("finished")
    }
}

let test = TestAsyncAfter()
test.goToPage(completionHandler: { finished in
    print("We have completed function")
    test.nextStep()
})

PlaygroundPage.current.needsIndefiniteExecution = true

Upvotes: 1

Related Questions