Skip to content

Remove isExecuting check in Toast.finish#123

Merged
devxoul merged 3 commits into
devxoul:masterfrom
ldiqual:lois-tests
Nov 1, 2017
Merged

Remove isExecuting check in Toast.finish#123
devxoul merged 3 commits into
devxoul:masterfrom
ldiqual:lois-tests

Conversation

@ldiqual

@ldiqual ldiqual commented Oct 17, 2017

Copy link
Copy Markdown
Contributor

Fixes #111

This reverts #109 and subsequently will impact this issue: #107.

As of Toaster 2.0.4 Toast.finish() skips setting isFinished=true and isExecuting=false when the operation is not executing. This causes an issue where calling cancel() right after show() will cause the operation queue to stall.

On the same vibe, since ToastCenter.currentToast didn't exclude cancelled and finished tasks, calling cancel() right after show() would cause currentToast to not be nil.

What's the bug

let toast = Toast(text: "text").show()
toast.cancel()

Since show() adds the operation to a background queue, it means Toast.start actually postpones the start() which causes cancel() to be called before start().

According to the cancel() docs:

You must change the value returned by isFinished to true and the value returned by isExecuting to false. You must make these changes even if the operation was cancelled before it started executing.

So cancel() needs to set isFinished=true and isExecuting=false. However in #109 we added a check that would prevent setting those flags if the operation is not executing. Since we're not setting those flags properly, the operation queue will call start() and wait for the operation to complete. However the operation will never complete because we ignore the start call if the operation is cancelled (see below).

Furthermore, according to start()'s documentation, we need to ignore finished/executing/cancelled operations because we're overriding the default implementation of start() which was performing those checks for us:

This method also performs several checks to ensure that the operation can actually run. For example, if the receiver was cancelled or is already finished, this method simply returns without calling main().

The fix

  • Removed the isExecuting guard in Toast.finish()

  • Removed a super.start() call since the docs specify that it must not be called

    Your custom implementation must not call super at any time`

    Instead, we're calling main() from start() directly.

  • Since ToastCenter.currentToast would return finished/cancelled operations, I fixed it by filtering those out

  • Added basic unit tests to make sure those issues are fixed, as well as one basic test that introspects the shared window.

Let me know if you have any question!

@ldiqual

ldiqual commented Nov 1, 2017

Copy link
Copy Markdown
Contributor Author

@devxoul Let me know if there's anything I can do to help you review this PR. Thanks!

@devxoul

devxoul commented Nov 1, 2017

Copy link
Copy Markdown
Owner

Oh sorry, I'm not having enough time to review this PR and other issues. I'm planning to rewrite the Toaster library to have tests and a solid architecture. By the way I believe that this PR would work properly so I'm gonna merge this and make a new release soon. Thanks!

@devxoul devxoul merged commit d5ff3ab into devxoul:master Nov 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[2.0.4] cancelAll() doesn't cancel toasts immediately

2 participants