使用 closures 代替 Gesture Recognizers 选择器

文章目录

原文 Adding Gesture Recognizers with Closures Instead of Selectors

添加UITapGestureRecognizer或任何 recognizer/target action 的最糟糕的部分是仅针对选择器参数实现新功能。今天,我想分享一个巧妙的技巧,让你添加不带选择器的手势识别器。

假设我们在View Controller中有一个UIImageView,我们想向其中添加一个UITapGestureRecognizer,以便在点击它时打印出一条语句.

通常,我们会创建一个 UITapGestureRecognizer 的实例,并将其目标设置为视图控制器及其选择器,因为我们会快速将它们组合在一起(myImageViewTapped(sender:UITapGestureRecognizer))。

这可能会有点多余,并且可能导致要添加交互性的每个子视图的函数的代码混乱。

我以为我可以快速扩展一下,以便为我的图像视图添加敲击手势识别器,但是然后我必须为每个识别器创建一个新功能,对吗?错误!利用关联对象的功能,我们实际上可以将闭包存储为扩展中的计算属性!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import UIKit

extension UIView {
// In order to create computed properties for extensions, we need a key to
// store and access the stored property
fileprivate struct AssociatedObjectKeys {
static var tapGestureRecognizer = "MediaViewerAssociatedObjectKey_mediaViewer"
}

fileprivate typealias Action = (() -> Void)?

// Set our computed property type to a closure
fileprivate var tapGestureRecognizerAction: Action? {
set {
if let newValue = newValue {
// Computed properties get stored as associated objects
objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
get {
let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action
return tapGestureRecognizerActionInstance
}
}

// This is the meat of the sauce, here we create the tap gesture recognizer and
// store the closure the user passed to us in the associated object we declared above
public func addTapGestureRecognizer(action: (() -> Void)?) {
self.isUserInteractionEnabled = true
self.tapGestureRecognizerAction = action
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
self.addGestureRecognizer(tapGestureRecognizer)
}

// Every time the user taps on the UIImageView, this function gets called,
// which triggers the closure we stored
@objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
if let action = self.tapGestureRecognizerAction {
action?()
} else {
print("no action")
}
}
}

现在,每当我们要将UITapGestureRecognizer添加到UIView或UIView子类(如UIImageView)时,都可以这样做,而无需为选择器创建关联的功能!这是一个例子:

1
2
3
sampleImageView.addTapGestureRecognizer {
print("image tapped")
}

没有UITapGestureRecognizers实例,没有targets,没有selectors,没有不必要的functions!