NSClickGestureRecognizer でシングルクリックとダブルクリックを識別

OS X でも 10.10 より GestureRecognizer が使えるようになりました。そこで、よせばいいのに NSClickGestureRecognizer を使ってみたいと思う人がいるかもしれません。その時にシングルクリックとダブルクリックでアプリの挙動を変えたい事もあるかもしれません。

そんな時にはシングルクリック用のNSClickGestureRecognizer とダブルクリック用のNSClickGestureRecognizer を実装すればいいと思うかもしれませんよね。

```swift
class MyViewController: NSViewController {
	// 省略
	override func viewDidLoad() {
		super.viewDidLoad()

		// 省略
		let singleClickGesture = NSClickGestureRecognizer(target: self, action: "singleClickGesture:")
		singleClickGesture.numberOfClicksRequired = 1 // single
		self.view.addGestureRecognizer(singleClickGesture)

		let doubleClickGesture = NSClickGestureRecognizer(target: self, action: "doubleClickGesture:")
		doubleClickGesture.numberOfClicksRequired = 2 // double
		self.view.addGestureRecognizer(doubleClickGesture)
	}
	// 省略
}
```

問題は、これでダブルクリックを行うと、シングルクリックとダブルクリックと両方のメソッドが呼ばれてしまいます。

```swift
	func singleClickGesture(gesture: NSClickGestureRecognizer) {
		if gesture.state == .Ended {
			print("single click")
		}
	}

	func doubleClickGesture(gesture: NSClickGestureRecognizer) {
		if gesture.state == .Ended {
			print("double click")
		}
	}
```
試しにダブルクリックしてみましょう。

```console
single click
double click
```
iOSの場合は `requireGestureRecognizerToFail` というメソッドが用意されていて、ダブルタップが失敗した時のみシングルタップを有効にできました。ところが OS X にはこの `requireGestureRecognizerToFail` がありません。OS X は後発なのでこの辺頼みますよと言いたい所です。

```
singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)
```
Developer Forums にも質問はありますが、答えは出ていません（2016年1月現在）。
https://forums.developer.apple.com/thread/21347

さて気を取り戻して、delegate を調べてみる事にします。

```swift
optional func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer,
shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool
```

> Asks the delegate if the current gesture recognizer must wait to recognize its gesture until the specified gesture recognizer fails.
> **Return Value**
> YES if otherGestureRecognizer must fail before gestureRecognizer is allowed to recognize its gesture. If you do not implement this method, the default return value is NO.
> **Discussion**
> This method is called once per attempt to recognize, so you can change the failure requirements dynamically. The two gesture recognizers do not have to belong to the same view hierarchy.
>
> Returning YES is guaranteed to set up the failure requirement; returning NO does not prevent the failure requirement from being set up by the other gesture recognizer.

なんだか使えそうな予感がします。これで、シングルクリックはダブルクリックが失敗した場合のみ有効とできそうですね。ちゃんと delegate が設定されているかどうか確認してください。

```swift
class MyViewController: NSViewController, NSGestureRecognizerDelegate {

	override func viewDidLoad() {
		super.viewDidLoad()

		// some code

		let singleClickGesture = NSClickGestureRecognizer(target: self, action: "singleClickGesture:")
		singleClickGesture.numberOfClicksRequired = 1 // single
		singleClickGesture.delegate = self
		self.view.addGestureRecognizer(singleClickGesture)

		let doubleClickGesture = NSClickGestureRecognizer(target: self, action: "doubleClickGesture:")
		doubleClickGesture.numberOfClicksRequired = 2 // double
		doubleClickGesture.delegate = self
		self.view.addGestureRecognizer(doubleClickGesture)
	}

	func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool {
		if let gestureRecognizer1 = gestureRecognizer as? NSClickGestureRecognizer,
		   let gestureRecognizer2 = otherGestureRecognizer as? NSClickGestureRecognizer
		   where gestureRecognizer1.numberOfClicksRequired == 1 && 
		         gestureRecognizer2.numberOfClicksRequired == 2 {
			return true
		}
		return false
	}
	// 省略
}
```

試しにダブルクリックしてみましょう。

```console
double click
```

では今度はシングルクリック

```console
single click
```

これで、うまくダブルクリックとシングルクリックを識別できるようになりました。