【发布时间】:2016-04-18 08:03:22
【问题描述】:
在我的项目中,我有几个视图控制器,它们是 UITableViewController、UIViewController 的子类,每个我想实现这种行为:
当用户在文本字段之外点击时,它应该关闭当用户在其中点击时可见的键盘。
我可以通过定义一个轻击手势识别器并关联一个选择器来关闭键盘来轻松实现它:
class MyViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureToDismissKeyboard()
}
private func configureToDismissKeyboard() {
let tapGesture = UITapGestureRecognizer(target: self, action: "hideKeyboard")
tapGesture.cancelsTouchesInView = true
form.addGestureRecognizer(tapGesture)
}
func hideKeyboard() {
form.endEditing(true)
}
}
由于我必须在多个视图控制器中实现相同的行为,我试图找出一种方法来避免在多个类中使用重复代码。
我的一个选择是定义一个BaseViewController,它是UIViewController 的子类,其中定义了所有上述方法,然后将我的每个视图控制器子类化为BaseViewController。这种方法的问题是我需要定义两个BaseViewControllers,一个用于UIViewController,一个用于UITableViewController,因为我使用了两者的子类。
我尝试使用的另一个选项是 - Protocol-Oriented Programming。所以我定义了一个协议:
protocol DismissKeyboardOnOutsideTap {
var backgroundView: UIView! { get }
func configureToDismissKeyboard()
func hideKeyboard()
}
然后定义它的扩展:
extension DismissKeyboardOnOutsideTap {
func configureToDismissKeyboard() {
if let this = self as? AnyObject {
let tapGesture = UITapGestureRecognizer(target: this, action: "hideKeyboard")
tapGesture.cancelsTouchesInView = true
backgroundView.addGestureRecognizer(tapGesture)
}
}
func hideKeyboard() {
backgroundView.endEditing(true)
}
}
在我的视图控制器中,我确认了协议:
class MyViewController: UITableViewController, DismissKeyboardOnOutsideTap {
var backgroundView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// configuring background view to dismiss keyboard on outside tap
backgroundView = self.tableView
configureToDismissKeyboard()
}
}
问题是 - 上面的代码因异常而崩溃:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyProject.MyViewController hideKeyboard]: unrecognized selector sent to instance 0x7f88c1e5d700'
为了避免这种崩溃,我需要在 MyViewControllerclass 中重新定义 hideKeyboard 函数,这违背了我避免重复代码的目的:(
如果我在这里做错了什么,或者有没有更好的方法来实现我的要求,请提出建议。
【问题讨论】:
-
看来,从 MyViewController 中,您想在 BaseViewControllers 中重用函数 hideKeyboard。但是您没有将 MyViewController 声明为 BaseViewControllers 的子类。
-
嘿,感谢您的回复,但请注意,由于我发布的问题中指定的原因,使用
BaseViewController是我试图避免的第一个选项。目前我正在尝试使用protocol-oriented programming代替它:) -
如果你使用面向协议的编程,你必须在你的 MyViewController 中实现 hideKeyboard,所以有重复的代码。该协议可帮助您定义要符合的“协议”。
-
啊,是真的。很有趣!
-
stackoverflow.com/questions/36184912/… 看看这个线程。也许它可以帮助你
标签: swift protocols uitapgesturerecognizer