Last active
March 4, 2019 09:47
-
-
Save mzaks/c69a33a2dcfb1e950206 to your computer and use it in GitHub Desktop.
Swift debounce function based GCD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/** | |
Creates and returns a new debounced version of the passed block which will postpone its execution until after wait seconds have elapsed since the last time it was invoked. | |
It is like a bouncer at a discotheque. He will act only after you shut up for some time. | |
This technique is important if you have action wich should fire on update, however the updates are to frequent. | |
Inspired by debounce function from underscore.js ( http://underscorejs.org/#debounce ) | |
*/ | |
public func dispatch_debounce_block(wait : NSTimeInterval, queue : dispatch_queue_t = dispatch_get_main_queue(), block : dispatch_block_t) -> dispatch_block_t { | |
var cancelable : dispatch_block_t! | |
return { | |
cancelable?() | |
cancelable = dispatch_after_cancellable(dispatch_time(DISPATCH_TIME_NOW, Int64(wait * Double(NSEC_PER_SEC))), queue, block) | |
} | |
} | |
// Big thanks to Claus Höfele for this function | |
// https://gist.github.com/choefele/5e5a981ed731472b80d9 | |
func dispatch_after_cancellable(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t) -> () -> Void { | |
var isCancelled = false | |
dispatch_after(when, queue) { | |
if !isCancelled { | |
block() | |
} | |
} | |
return { | |
isCancelled = true | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCTest | |
class debounceTest: XCTestCase { | |
func test_dispatch_debounce_block_create_with_no_execute() { | |
// given | |
let expectation = expectationWithDescription("expect block to be executed"); | |
var counter = 0 | |
let bouncedBlock = dispatch_debounce_block(0.1){ | |
counter++ | |
} | |
// when | |
// no executed | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()){ | |
// fulfill expectation after 0.5 seconds | |
expectation.fulfill() | |
} | |
// then | |
waitForExpectationsWithTimeout(1) { | |
error in | |
XCTAssertEqual(counter, 0, "never executed") | |
} | |
} | |
func test_dispatch_debounce_block_executing_only_once() { | |
// given | |
let expectation = expectationWithDescription("expect block to be executed"); | |
var counter = 0 | |
let bouncedBlock = dispatch_debounce_block(0.1){ | |
counter++ | |
} | |
// when | |
// execute bounce block 10 time in a row | |
for _ in 1 ... 10 { | |
bouncedBlock() | |
} | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()){ | |
// fulfill expectation after 0.5 seconds | |
expectation.fulfill() | |
} | |
// then | |
waitForExpectationsWithTimeout(1) { | |
error in | |
// only one execution should be performed | |
XCTAssert(counter == 1, "called only once") | |
} | |
} | |
func test_dispatch_debounce_block_executing_twice() { | |
// given | |
let expectation = expectationWithDescription("expect block to be executed"); | |
var counter = 0 | |
let bouncedBlock = dispatch_debounce_block(0.1){ | |
counter++ | |
} | |
// when | |
// execute bounce block 10 time in a row | |
for _ in 1 ... 10 { | |
bouncedBlock() | |
} | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()){ | |
// execute bounce block after 0.5 seconds | |
bouncedBlock() | |
} | |
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()){ | |
// fulfill expectation after 2 seconds | |
expectation.fulfill() | |
} | |
// then | |
waitForExpectationsWithTimeout(3) { | |
error in | |
XCTAssertEqual(counter, 2, "called twice") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment