Foobar
Foobar

Reputation: 8487

Screen not updating when dispatch_async finishes executing code

I have the following code for a delete button in a IOS 9 custom keyboard app extension:

func deletekeyPressed(sender: UIButton!) {

    NSLog("-------------------")
    NSLog("Pressing delete key")

    sender.setTitle("Deleting...", forState: .Normal)
    sender.userInteractionEnabled = false



    dispatch_async(dispatch_get_main_queue()) {
    NSLog("Starting delete function")

        while(self.textDocumentProxy.hasText()) {
         //   NSLog("Deleting 3 times")
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
        }

        for _ in 1..<2000 {
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
        }

        sender.setTitle("Clear", forState: .Normal)
        sender.userInteractionEnabled = true

        NSLog("Finishing delete function")
    }

}

The code is supposed to do the following: When the delete key is pressed its text will switch from "Clear" to "Deleting..." until all the text is finished deleting. This is to prevent the user from thinking the keyboard is crashing meanwhile text is being deleted.

The problem is that the solution only partially works. The delete key's text does change to "Deleting..." until the code inside of dispatch_async finishes and then it does revert back to the default delete button text "Clear". The problem is that the Iphone's screen does not show that the text is deleted right after the function is finished calling.

This results in the delete button's text switching back to "Clear" before text is actually shown as deleted. I do not know why the rest of screen does not update as soon as the async task finishes executing (only the button's text updates).

Here is a video demonstrating the problem:

bdemo

Why is the screen not updating (besides the delete button) when the async task finishes?

Upvotes: 0

Views: 63

Answers (2)

Justin
Justin

Reputation: 434

Your code is running too fast for you to observe anything. If you want to visually observe the deletions you should put the code you're running in a NSTimer method that fires every 0.1 seconds or something.

Upvotes: 0

NeverHopeless
NeverHopeless

Reputation: 11233

From your code it looks to me that you are engaging the main thread in doing some CPU intensive work, so it is unable to update the UI. (Haven't reproduced by my own).

The problematic part appears to be this:

dispatch_async(dispatch_get_main_queue())

You should do CPU intensive work in background thread and continue the main thread once it is done.

Perhaps trying like this may help:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

        NSLog("Starting delete function")

        while(self.textDocumentProxy.hasText()) {
         //   NSLog("Deleting 3 times")
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
        }

        for _ in 1..<2000 {
            (self.textDocumentProxy as UIKeyInput).deleteBackward()
        }

    // Wait to complete async work and continue the UI update in main thread
    dispatch_sync(dispatch_get_main_queue(), ^{
        // update some UI

        sender.setTitle("Clear", forState: .Normal)
        sender.userInteractionEnabled = true

        NSLog("Finishing delete function")
    });
});

Upvotes: 0

Related Questions