9

I am writing a program using Swift 3.1 and Xcode 8.3.3. I want to create a class, responsible for moving entire view when keyboard appears and disappears. But I faced difficulties with creating custom Selector with parameters from string. To show or hide keyboard we need function:

func keyboardWillShow(notification: Notification) {
//Code moving view when keyboard appears
}

I am trying to create a selector like this:

let selector = Selector(("keyboardWillShow")
NotificationCenter.default.addObserver(view, selector: selector, name: .UIKeyboardWillShow, object: anyView.view.window)

It is compiling, but when keyboard appears, it crashes. Because it is independent class I cannot use this construction:

#selector(keyboardWillShow)

Because it transforms Swift function to Objective-C function (adding @objc). So question is: how to create a Selector form with parameters string?

P. S. I can put the whole code there but I don't want question to be very big, so I will edit question if somebody asks...

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Alex
  • 1,038
  • 2
  • 12
  • 32

2 Answers2

14

Here is what you want, Selector with string type and Notification parameter argument

Swift 4

NotificationCenter.default.addObserver(self, selector: Selector(("showKeyboard:")), name:NSNotification.Name.UIKeyboardWillShow, object: nil)

var keyboardHeight = 0.0
//-------------------
@objc func showKeyboard(_ sender: Notification) {
    keyboardWillShow(sender: sender as NSNotification, adjustHeight: 150)
    print("sender - \(sender)")
}

//-------------------
func keyboardWillShow(sender: NSNotification, adjustHeight: CGFloat) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        keyboardHeight = Double(keyboardSize.height)
        // do your calculations
    }
}


Swift 3

NotificationCenter.default.addObserver(view, selector: Selector(("keyboardWillShow:")), name: .UIKeyboardWillShow, object: anyView.view.window)

func keyboardWillShow(_ notification: Notification) { 
       keyboardWillShow(sender: sender as NSNotification, adjustHeight: 150)
        print("sender - \(sender)")

} 



Here are normal selector, according to language support
Swift 4

NotificationCenter.default.addObserver(self, selector: #selector(self.showKeyboard(sender:)), name:NSNotification.Name.UIKeyboardWillShow, object: nil)

var keyboardHeight = 0.0

    //-------------------
    @objc func showKeyboard(sender: NSNotification) {
        keyboardWillShow(sender: sender, adjustHeight: 150)
    }

    //-------------------
    func keyboardWillShow(sender: NSNotification, adjustHeight: CGFloat) {
        if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            keyboardHeight = Double(keyboardSize.height)
            // your operations here
        }
    }


Swift 3

NotificationCenter.default.addObserver(self, selector: #selector(self.showKeyboard(sender:)), name:NSNotification.Name.UIKeyboardWillShow, object: nil)

var keyboardHeight = 0.0

    //-------------------
    func showKeyboard(sender: NSNotification) {
        keyboardWillShow(sender: sender, adjustHeight: 150)
    }

   //-------------------
    func keyboardWillShow(sender: NSNotification, adjustHeight: CGFloat) {
        if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            keyboardHeight = Double(keyboardSize.height)
            // your operations here
        }
    }
Krunal
  • 77,632
  • 48
  • 245
  • 261
  • Thank you for your answer, but it is not quite the same. Question is how to create selector with parameters from string. Moreover, even in swift 3.1 you should not use NS functions or variables without special need. Download my project please and see how not to use NSValue. – Alex Jun 09 '17 at 13:11
  • But please, can I make some more comments? – Alex Jun 09 '17 at 14:07
  • First, remove @objc , it causes warning. Second: I think we do not need two functions: showKeyboard and keyboardWillShow. We can easily unite them in one. In fact the most useful part is this: showKeyboard(_ sender: Notification) This symbol "_" I was looking for! Thank you!!! – Alex Jun 09 '17 at 14:11
  • I do not know how to edit other answers but it does not matter, it is working! Other people will see it too. Thank You very much again!!! – Alex Jun 09 '17 at 14:16
  • Please paste your code here in comment area.. as qualitative question and answer are useful rather than simple statements. – Krunal Jun 09 '17 at 14:19
  • NotificationCenter.default.addObserver(view, selector: Selector(("keyboardWillShow:")), name: .UIKeyboardWillShow, object: anyView.view.window) – Alex Jun 09 '17 at 14:20
  • func keyboardWillShow(_ notification: Notification) { //... } – Alex Jun 09 '17 at 14:20
  • But screen, where you calling this also must have func keyboardWillShow(_ notification: Notification) { //... } It is important! – Alex Jun 09 '17 at 14:21
  • Why are you using double parentheses around the function name? – filip.karas Aug 17 '18 at 06:05
2

This way works,

override func viewDidLoad() {
    super.viewDidLoad()
// put it wherever you want
 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(showKeyboard), name:UIKeyboardWillShowNotification, object: nil)
}

func showKeyboard(sender: NSNotification) {
    keyboardWillShow(sender, adjustHeight: 150)
}

func keyboardWillShow(sender: NSNotification, adjustHeight: CGFloat) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        keyboardHeight = keyboardSize.height
 // do your calculations
    }
}

This will helps you to achieve your expected result.

Praveen Kumar
  • 298
  • 2
  • 15
  • Yes, this works, but main idead to avoid writing this NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillShow), name:UIKeyboardWillShowNotification, object: nil) and the same long line for hiding keyboard in ViewDidLoad. – Alex Jun 09 '17 at 07:44
  • This is the generic approach whenever the keyboard appears or disappears, the selector method gets called. So what is your expectation?! – Praveen Kumar Jun 09 '17 at 07:47
  • I want to write a class, general class. So, idea is to avoid of duplicate of long code. I can do yours approach on each view, but I want to avoid of doing it. – Alex Jun 09 '17 at 07:51
  • you can write `keyboardWillShow ` in a base class and inherit it to the other classes to access the method but you have to use `NSNotificationCenter` at whichever class you need. – Praveen Kumar Jun 09 '17 at 07:55
  • It seems only one way now... Thank you. But still, parameters are not available in selectors? – Alex Jun 09 '17 at 07:57
  • Thank you for idea but I doubt that I should do like this. There is much more better way to calculate height of keyboard... – Alex Jun 09 '17 at 08:05
  • This is how you can get the `let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()` vaue. you can get the height and width like this `keyboardSize.height` and `keyboardSize.width`. – Praveen Kumar Jun 09 '17 at 08:08
  • Yes, I know how to move keyboard. Problem is I do not know how to add observer with specific selector. But your idea to make a class and inherit from it looks very good. – Alex Jun 09 '17 at 08:11
  • You can add the observer code wherever you want but the viewDidLoad will be the apt one. And the selector can be any method name you write. Try it. If my answer works mark it as accepted answer. Thanks! – Praveen Kumar Jun 09 '17 at 09:00