我有一个名为FooFramework的Cocoa Touch Framework。
在其中,我想管理键盘显示时所选视图在Y轴上的向上移动。我创建了一个KeyboardManager
类。这是它的外观:
import UIKit
public class KeyboardManager {
var notifyFromObject: Any?
var observer: Any
public var viewsToPushUp: [UIView] = []
public init(observer: Any, viewsToPushUp: [UIView], notifyFromObject: Any? = nil) {
self.observer = observer
self.notifyFromObject = notifyFromObject
self.viewsToPushUp = viewsToPushUp
}
public func pushViewsUpWhenKeyboardWillShow(){
let notificationCenter = NotificationCenter.default
print(self)
notificationCenter.addObserver(self.observer, selector: #selector(FooFramework.KeyboardManager.pushViewsUp), name: NSNotification.Name.UIKeyboardWillShow, object: notifyFromObject)
}
@objc public func pushViewsUp(notification: NSNotification) {
if let keyboardRectValue = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardHeight = keyboardRectValue.height
for view in viewsToPushUp {
view.frame.origin.y -= keyboardHeight
}
}
}
}
然后,我在名为Bar的iOS应用程序中导入此FooFramework。为了测试FooFramework,我想推高UITextField
。这是代码:
import UIKit
import FooFramework
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let kb = KeyboardManager(observer: self, viewsToPushUp: [textField], notifyFromObject: nil)
kb.pushViewsUpWhenKeyboardWillShow()
}
func pushViewsUp(notification: NSNotification) {
print("This should not be printed")
}
}
我的问题是This should not be printed
出现在控制台中,pushViewsUp
中的KeyboardManager
方法永远不会被调用。尽管我为选择器使用了一个完全限定的名称,但它坚持使用ViewController中的pushViewsUp
。这让我疯了。
如果我从ViewController中删除pushViewsUp
,我会收到以下错误:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Bar.ViewController pushViewsUpWithNotification:]: unrecognized selector sent to instance 0x7fc540702d80'
我需要做什么才能使选择器正确指向FooFramework.KeyboardManager.pushViewsUp
?
答案 0 :(得分:2)
我认为您需要使用self
而不是self.observer
作为addObserver
函数中的观察者。
此外,您需要在函数范围之外声明kb
变量,以便管理员检测通知。
示例:
import UIKit
import FooFramework
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
var kb: KeyboardManager?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
kb = KeyboardManager(observer: self, viewsToPushUp: [textField], notifyFromObject: nil)
kb?.pushViewsUpWhenKeyboardWillShow()
}
}
KeyboardManager
更改:
public func pushViewsUpWhenKeyboardWillShow() {
let notificationCenter = NotificationCenter.default
print(self)
notificationCenter.addObserver(self,
selector: #selector(FooFramework.KeyboardManager.pushViewsUp),
name: NSNotification.Name.UIKeyboardWillShow,
object: notifyFromObject)
}
答案 1 :(得分:1)
除了Justin建议的一切都是正确的之外,在完全解决问题之前还有一些事情需要考虑。
var observer:任何
在其中是不必要的。你应该删除它。
这就是您的KeyboardManager类的外观:
import UIKit
public class KeyboardManager {
var notifyFromObject: Any?
public var viewsToPushUp: [UIView] = []
public init(viewsToPushUp: [UIView], notifyFromObject: Any? = nil){
self.notifyFromObject = notifyFromObject
self.viewsToPushUp = viewsToPushUp
//remember KeyboardManager itself is observing the notifications and moving the views it received from the ViewController. Hence we use self.
NotificationCenter.default.addObserver(self, selector: #selector(FooFramework.KeyboardManager.pushViewsUp), name: NSNotification.Name.UIKeyboardWillShow, object: notifyFromObject)
}
@objc public func pushViewsUp(notification: NSNotification) {
if let keyboardRectValue = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardHeight = keyboardRectValue.height
for view in viewsToPushUp {
view.frame.origin.y -= keyboardHeight
}
}
}
}
在获得正确的行为之前,您还需要正确使用框架。
只要具有textField的ViewController处于活动状态,您就应该将KeyboardManagerInstance的生命周期延长到活动状态。你可以通过Justin建议将它声明为ViewController中的实例变量来实现。你这样做的方式,你的KeyboardManager实例是一个局部变量,它会在函数超出范围时立即创建并立即释放。要验证这一点,您可以将其添加到KeyboardManager类并检查:
deinit {
print("KeyboardManager is perhaps dying an untimely death.")
}
最后你的ViewController类应该只做这个
import UIKit
import FooFramework
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
var kb: KeyboardManager?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
kb = KeyboardManager(viewsToPushUp: [textField], notifyFromObject: nil)
//observe that there is no observer param in the initializer and also no "pushViewsUpWhenKeyboardWillShow" call as that behavior has already been moved to init itself.
}
}