Class UITapGestureRecognizer

Class UITapGestureRecognizer is a subclass of UIGestureRecognizer.

Source code in

  1. Class AppDelegate: unchanged.
  2. Class ViewController: unchanged.
  3. Class View: added methods init(coder:), singleAction(_:), doubleAction(_:), and wearOff(). Note that the last parameter of dispatch_after is a dispatch_block_t, not a selector.

Create the project

Class View is a subclass of UILabel.

Recognizing single and double taps

The single tap recognizer must not be allowed to recognize a single tap until the double tap recognizer has told it that the tap is not the first half of a double tap. See requireGestureRecognizerToFail:.

Int64 and UInt64

NSEC_PER_SEC = 1,000,000,000 = 109 is the number of nanoseconds per second. I wanted to say 3.5 * NSEC_PER_SEC instead of 3500000000, but Swift wouldn’t let me multiply them because 3.5 is a Double and NSEC_PER_SEC is a UInt64. I could have converted NSEC_PER_SEC to Double, multiplied it by 3.5, and converted the product back to the Int64 required by dispatch_time,

	let delay: Int64 = Int64(3.5 * Double(NSEC_PER_SEC));
but it was simpler to write 3500000000. Note that the 3500000000 was parsed correctly even though it was bigger than the maximum 32-bit integer 231 − 1 = 2,147,483,647. See Literals.

Things to try

  1. Change the 3500000000 to 3_500_000_000 to make it easier to read. See Integer Literals.

  2. Replace the methods singleAction(_:) and doubleAction(_:) by the following. It does the work of either one.
    	func action(recognizer: UITapGestureRecognizer) -> Void {
    		text = String(recognizer.numberOfTapsRequired); //Convert Int to String.
    		let t: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, delay);
    		dispatch_after(t, dispatch_get_main_queue(), wearOff);

  3. Change
    		dispatch_after(t, dispatch_get_main_queue(), wearOff);
    to use a closure.
    		dispatch_after(t, dispatch_get_main_queue(), {self.text = "0";});

  4. Detect a triple tap.

  5. If a second gesture is detected while a previous gesture is still displaying its number, we should cancel the call to wearOff() that the previous gesture scheduled.