我需要一个外部的键盘管理器类,因为我有许多需要该服务的Viewcontrollers。我编写的代码在物理上位于Viewcontroller中时工作得很完美,但是一旦我通过Keyboard Manager类调用它,我就会得到" libc ++ abi.dylib:以NSException类型的未捕获异常终止"。
我知道这个错误通常意味着有一些与IBOutlet断开的连接,但在这种情况下我不确定这是如何相关的。
该类基本上告诉viewcontroller中的scrollview调用它向上滚动并使文本字段可见,在编辑完成时恢复状态并在点击scrollview时隐藏键盘。我也尝试使用与KeyboardManagerDelegate相同的方法,结果相同。我也尝试在任何可能的组合中将activeField,vc和scrollView变量更改为弱,但它没有改变任何内容。
这里是KeyboardManager的代码:
import UIKit
class KeyboardManager {
var activeField: UITextField?
var vc: UIViewController!
var scrollView: UIScrollView!
init(_ vc: UIViewController, _ scrollView: UIScrollView, _ activeField: UITextField?) {
self.vc = vc
self.scrollView = scrollView
self.activeField = activeField
NotificationCenter.default.addObserver(vc, selector: #selector(keyboardDidShow), name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(vc, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
let tap = UITapGestureRecognizer(target: vc, action: #selector(hideKeyboard))
tap.numberOfTouchesRequired = 1
self.scrollView.addGestureRecognizer(tap)
}
@objc func keyboardDidShow(notification: NSNotification) {
if let activeField = activeField, let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
print("Keyboard height is \(keyboardSize.height)")
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
scrollView.scrollRectToVisible(activeField.frame, animated: true)
}
}
@objc func keyboardWillHide(notification: NSNotification) {
let contentInsets = UIEdgeInsets.zero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
@objc func hideKeyboard() {
activeField?.resignFirstResponder()
}
}
Viewcontroller中的相关代码在这里:
class ViewController: UIViewController, UITextFieldDelegate {
weak var activeField: UITextField?
var keyboardManager: KeyboardManager!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
keyboardManager = KeyboardManager(self, scrollView, activeField)
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.activeField = nil
}
}
提前感谢有关如何使这项工作的任何见解,因为我的项目现在处于暂停状态,直到我能够解决这个问题,如果我要复制和放弃,那将是太多的重复。将此代码粘贴到我拥有的每个ViewController中。
更新:我刚刚在自己的项目中发现了一些我以前没有看到的有趣内容:KeyboardManagerDrama [1731:3465043] 由于未捕获的异常终止应用程序' NSInvalidArgumentException',原因:&#39 ; - [KeyboardManagerDrama.ViewController keyboardDidShowWithNotification:]:无法识别的选择器发送到实例0x15fe18790' 所以我想也许是因为我将观察者设置为vc但是viewcontroller没有选择器功能。如果是这种情况,如何在将查看器功能保持在KeyboardManager中的同时将观察者设置为viewcontroller?
答案 0 :(得分:0)
崩溃的原因是您添加了错误的通知观察者。请尝试以下代码。
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
let tap = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
将vc
替换为self
。在ViewController
您没有方法keyboardDidShow
,keyboardWillHide
,hideKeyboard
。这就是你崩溃的原因
另外,在ViewController中创建activeField
时,您应该将textField
替换为KeyboardManager
,如下所示:
keyboardManager = KeyboardManager(self, scrollView, textField)
答案 1 :(得分:0)
代码有两个问题: 首先观察者设置在一个视图控制器上,当它应该像@trungduc那样自我设置时说:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
let tap = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
其次,在KeyboardManager实例中没有更新activeField属性,因此将其添加到Viewcontroller解决了100%的问题:
weak var activeField: UITextField? {
didSet {
keyboardManager.activeField = activeField
}
}