App crashing when adding completion to the observer - swift

I'm trying to add a block to the notification observer, but the app is getting crashed when moving foreground and background. If I'm adding method to observer its working fine, only in case of block its getting crashed. Here is my code which I'm trying for the same.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(foregroundEntered(closure:)), name: UIApplication.willEnterForegroundNotification, object: nil)
// Do any additional setup after loading the view.
}
#objc func foregroundEntered(closure: () -> Void) {
/// do some stuff
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
}
}
Thanks in advance.

Replace
#objc func foregroundEntered(closure: () -> Void) {
With
#objc func foregroundEntered(_ notif: NSNotification) {
And change
NotificationCenter.default.addObserver(self, selector: #selector(foregroundEntered), name: UIApplication.willEnterForegroundNotification, object: nil)

Related

How to move StatView programmatically when keyboard shows

I have a login page which has two textviews and a button in a stackView
I'm trying to move the stackview when the keyboard shows and also disappears as I want to know how to do this programmatically
iOS sends 2 notifications when keyboard will show/hide
UIKeyboardWillShow
UIKeyboardWillHide
What you can do, is observe those notifications, and move the frame of your stackView such as
#objc func keyboardWillShow() {
if stackView.frame.origin.y == 0 {
stackView.frame.origin.y -= 200
}
}
#objc func keyboardWillHide() {
if stackView.frame.origin.y != 0 {
stackView.frame.origin.y = 0
}
}
And here is how to observe those notification. (use this code in your viewDidLoad function)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: Notification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: Notification.Name.UIKeyboardWillHide, object: nil)
Swift 4.2
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIWindow.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIWindow.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
print("keyboardWillShow")
}
#objc func keyboardWillHide(notification: NSNotification){
print("keyboardWillHide")
}
If still got any error check below link:
LINK FOR KEYBOARD HIDE/SHOW

App crashing: Exception - unrecognised selector sent to instance

I've got a UITableviewController with following logic to slide up / down the entire view once the keyboard toggles like so:
class ChatDetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// variables...
override func viewDidLoad() {
super.viewDidLoad()
// do stuff...
NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillShow:")), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillHide:")), name: UIResponder.keyboardWillHideNotification, object: nil)
// do other stuff...
}
...
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.view.frame.origin.y -= keyboardSize.height
}
}
func keyboardWillHide(notification: NSNotification) {
self.view.frame.origin.y = 0
}
...
}
Toggling the keyboard then crashes the App with following exception: ChatDetailViewController keyboardWillShow:]: unrecognized selector sent to instance 0x7f82fc41fdf0
The error message seems clear at first glance but I still can't figure out what's wrong with my selector. No code warnings, no typos,...
What is it I'm doing wrong here?
In Swift 4 i have previously used in like this
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
#objc func keyboardWillShow(notification: NSNotification) {
print("keyboardWillShow")
}
#objc func keyboardWillHide(notification: NSNotification){
print("keyboardWillHide")
}
In Swift 5 they renamed the way to access the keyboard notifications to go through UIResponder:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
Three issues:
The creation of the selector is wrong (use #selector)
The signature of the action is wrong (missing underscore)
The action must be marked as #objc
And the type in Swift is Notification without NS prefix
override func viewDidLoad() {
super.viewDidLoad()
// do stuff...
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
// do other stuff...
}
...
#objc func keyboardWillShow(_ notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.view.frame.origin.y -= keyboardSize.height
}
}
#objc func keyboardWillHide(_ notification: Notification) {
self.view.frame.origin.y = 0
}
...
You forgot to add #objc part:
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide),
name: UIResponder.keyboardWillHideNotification,
object: nil)
#objc func keyboardWillShow(_ sender: Notification) {}
#objc func keyboardWillHide(_ sender: Notification) {}

viewWillEnterForeground issue

xcode10.1
swift4.2
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.viewWillEnterForeground(_:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
}
I used to use code above to run method when the app enter foreground. However, this code does not run anymore. There is no UIApplicationWillEnterForeground after NSNotification.Name.
Anyone knows how to add notification method when the app enter foreground in VC?
Add notification observer in viewDidLoad of the view controller
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.viewWillEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func viewWillEnterForeground(_ notification: Notification) {
//Work anything app enter in background
}
The post-notification fire from app delegate willEnterForgroundMethod
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
NotificationCenter.default.post(name: UIApplication.willEnterForegroundNotification, object: nil)
}

Unrecognized selectors sent to instance, Notification center getting the Keyboard size

If I try to tap into my textfields I get an error, related to these few lines of code that try to get the size of the keyboard on a mobile ios device. The Notification Center lines of code are inside the overriding ViewDidAppear.
NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillShow:")), name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillHide:")), name: UIResponder.keyboardDidHideNotification, object: nil)
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.bottomConstraint.constant = keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
self.bottomConstraint.constant = 0
}
Use the type safe syntax
#selector(keyboardWillShow)
and
#objc func keyboardWillShow(_ notification: Notification) { ...
However I highly recommend to use the modern closure based syntax
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { [weak self] notification in
if let userInfo = notification.userInfo,
let keyboardSize = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self?.bottomConstraint.constant = keyboardSize.height
}
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { [weak self] _ in
self?.bottomConstraint.constant = 0
}
Try Following code :
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("notification: Keyboard will show")
}
}
#objc func keyboardWillHide(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
}
}
You can try this:
This code in viewDidLoad():
// Do any additional setup after loading the view.
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
and then add this in ViewController
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("Keyboard opened \(keyboardSize)")
}
}
#objc func keyboardWillHide(notification: NSNotification) {
print("Keyboard hide")
}
Hope this will help.
You should deregister any notification you register in a view.
func registerForKeyboardNotifications()
{
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func deRegisterFromKeyboardNotifications()
{
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWasShown(_ notification: NSNotification)
{
//todo
}
#objc func keyboardWillBeHidden(_ notification: NSNotification)
{
//todo
}
override func viewDidLoad() {
super.viewDidLoad()
registerForKeyboardNotifications()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
deRegisterFromKeyboardNotifications()
}
You've got this error because of notification parameter. With current signature you should use:
#selector(keyboardWillShow(notification:))
#selector(keyboardWillHide(notification:))
Or rewrite your methods in that way:
#objc func keyboardWillShow(_ notification: Notification) {
// Code
}
#objc func keyboardWillHide(_ notification: Notification) {
// Code
}
And use the next syntax:
#selector(keyboardWillShow(_:))
#selector(keyboardWillHide(_:))
Edited:
You can also use simplified syntax:
#selector(keyboardWillShow)
#selector(keyboardWillHide)
Use like below code
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(notification:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
// Your code
}
}
#objc func keyboardWillHide(notification: NSNotification) {
// Your code
}
Hope this works, If any doubt plz comment.

swift screen move when keyboard appears

I have a textview and a text field on my screen and I want move screen when edit textview.
This is my code
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: .UIKeyboardWillShow, object: nil)
// NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: .UIKeyboardWillHide, object: nil)
print("addd observer")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
// NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
#objc func keyboardWillShow(_ sender: Notification) {
let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
print("keyboardwillshow")
ksize = keyboardSize?.height
}
#objc func textViewDidBeginEditing(_ textView: UITextView) {
print("textviewedit")
boxview.frame.origin.y -= ksize
print("textview")
}
#objc func textViewDidEndEditing(_ textView: UITextView) {
print("textvieweditend")
boxview.frame.origin.y = 0
}
It works when I just edit textview. However, if I edit the textview right after focus on the textfield(without exit keyboard) it doens't work.
I already checked that textviewDidBeginEditing() is called but the screen doesn't move.. How can I solve this? All advises are welcome!
I add self.view.Layoutifneeded() to keyboardwillchange() and it works!! thanks everybody.