通过协议扩展将选择器与协议方法的默认实现一起使用
Using selectors with default implementations of protocol methods via protocol extensions
我正在尝试制定一个 ViewController 可以实施的协议来调整其视图以适应键盘 show/hide。
protocol KeyboardAdaptable {
func keyboardWillShow(notification: NSNotification)
func keyboardWillHide(notification: NSNotification)
func addKeyboardNotificationObservers()
}
extension KeyboardAdaptable where Self: UIViewController, Self: NSObject {
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
}
func addKeyboardNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
}
错误:"Argument of #selector refers to instance methods 'keyboardWillShow' that is not exposed to Objective-C."
我知道选择器是 Objective-C 的一个特性并且引用的函数必须兼容。我试图通过标记协议本身以及使用 @objc 注释的方法来解决这个问题,但是编译器坚持我也使用 @objc 标记协议扩展中的默认实现。当我这样做时,它对我大喊大叫,要求我删除 @objc 注释,因为 "@objc 只能与 类 的成员、@objc 协议和 类 的具体扩展一起使用"(即不在协议扩展中?)
有谁知道实现这个目标的方法吗?我知道乍一看似乎没有办法解决它,但我也知道 UIViewController 是 NSObject 的子项,通常允许 UIViewController 上的实例方法成为选择器的目标。我想通过对我的协议扩展施加约束,要求它是 UIViewController 的子类,我可以将其中包含的默认实现作为选择器的目标。
想法?
无法完成。
每个人首先都认为这是一个很酷的想法,(包括我自己)但事实并非如此。
Swift 协议扩展对 Objective-C 不可见。对此无能为力。即使使用 #selector
也不起作用,因为:
您的协议功能仅在协议扩展中定义。
人们不断尝试通过协议扩展将 Objective-C 可调用功能(选择器、委托方法等)注入 class。对不起。
我完全同意之前的回答——这是做不到的。但是,我决定对您的代码进行一些愚弄,并创建我能找到的最可接受的解决方案。也许它会派上用场:
class KeyboardAdapter {
private weak var view: UIView!
init(view: UIView) {
self.view = view
addKeyboardNotificationObservers()
}
@objc
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
@objc
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y += keyboardSize.height
}
}
}
private func addKeyboardNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
}
protocol KeyboardAdaptable: class {
var keyboardAdapter: KeyboardAdapter! { get set }
func configureAdapter()
}
extension KeyboardAdaptable where Self: UIViewController {
func configureAdapter() {
keyboardAdapter = KeyboardAdapter(view: self.view)
}
}
我正在尝试制定一个 ViewController 可以实施的协议来调整其视图以适应键盘 show/hide。
protocol KeyboardAdaptable {
func keyboardWillShow(notification: NSNotification)
func keyboardWillHide(notification: NSNotification)
func addKeyboardNotificationObservers()
}
extension KeyboardAdaptable where Self: UIViewController, Self: NSObject {
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0{
self.view.frame.origin.y -= keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
}
func addKeyboardNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
}
错误:"Argument of #selector refers to instance methods 'keyboardWillShow' that is not exposed to Objective-C."
我知道选择器是 Objective-C 的一个特性并且引用的函数必须兼容。我试图通过标记协议本身以及使用 @objc 注释的方法来解决这个问题,但是编译器坚持我也使用 @objc 标记协议扩展中的默认实现。当我这样做时,它对我大喊大叫,要求我删除 @objc 注释,因为 "@objc 只能与 类 的成员、@objc 协议和 类 的具体扩展一起使用"(即不在协议扩展中?)
有谁知道实现这个目标的方法吗?我知道乍一看似乎没有办法解决它,但我也知道 UIViewController 是 NSObject 的子项,通常允许 UIViewController 上的实例方法成为选择器的目标。我想通过对我的协议扩展施加约束,要求它是 UIViewController 的子类,我可以将其中包含的默认实现作为选择器的目标。
想法?
无法完成。
每个人首先都认为这是一个很酷的想法,(包括我自己)但事实并非如此。
Swift 协议扩展对 Objective-C 不可见。对此无能为力。即使使用 #selector
也不起作用,因为:
您的协议功能仅在协议扩展中定义。
人们不断尝试通过协议扩展将 Objective-C 可调用功能(选择器、委托方法等)注入 class。对不起。
我完全同意之前的回答——这是做不到的。但是,我决定对您的代码进行一些愚弄,并创建我能找到的最可接受的解决方案。也许它会派上用场:
class KeyboardAdapter {
private weak var view: UIView!
init(view: UIView) {
self.view = view
addKeyboardNotificationObservers()
}
@objc
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
@objc
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y += keyboardSize.height
}
}
}
private func addKeyboardNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
}
protocol KeyboardAdaptable: class {
var keyboardAdapter: KeyboardAdapter! { get set }
func configureAdapter()
}
extension KeyboardAdaptable where Self: UIViewController {
func configureAdapter() {
keyboardAdapter = KeyboardAdapter(view: self.view)
}
}